Пример #1
0
        static LNode ToLNodeCore(ILNode node)
        {
            var attrs = VList <LNode> .Empty;

            for (int i = node.Min; i < -1; i++)
            {
                attrs.Add(ToLNodeCore(node[i]));
            }

            switch (node.Kind)
            {
            case LNodeKind.Id:
                return(LNode.Id(attrs, node.Name, node.Range, node.Style));

            case LNodeKind.Literal:
                return(LNode.Literal(attrs, node.Value, node.Range, node.Style));

            default:
                var args = VList <LNode> .Empty;
                for (int i = 0, max = node.Max; i <= max; i++)
                {
                    args.Add(ToLNodeCore(node[i]));
                }
                var target = ToLNodeCore(node.Target);
                return(LNode.Call(attrs, target, args, node.Range, node.Style));
            }
        }
        // Parse the list of variables provided in the GUI
        public static Dictionary <Symbol, LNode> ParseVarList(IEnumerable <LNode> varList)
        {
            var vars = new Dictionary <Symbol, LNode>();

            foreach (LNode assignment in varList)
            {
                {
                    LNode expr, @var;
                    if (assignment.Calls(CodeSymbols.Assign, 2) && (@var = assignment.Args[0]) != null && (expr = assignment.Args[1]) != null)
                    {
                        if ([email protected])
                        {
                            throw new ArgumentException("Left-hand side of '=' must be a variable name: {0}".Localized(@var));
                        }

                        // For efficiency, try to evaluate the expression in advance
                        try { expr = LNode.Literal(Eval(expr, vars)); } catch { }                               // it won't work if expression uses X or Y
                        vars.Add(@var.Name, expr);
                    }
                    else
                    {
                        throw new ArgumentException("Expected assignment expression: {0}".Localized(assignment));
                    }
                };
            }
            return(vars);
        }
Пример #3
0
        public static LNode getScopedProperty(LNode node, IMacroContext context)
        {
            LNode key;

            if (node.ArgCount >= 1 && !(key = context.PreProcess(node.Args[0])).IsCall)
            {
                var keyValue = key.IsId ? key.Name : key.Value;
                var @default = node.Args[1, node];
                var result   = context.ScopedProperties.TryGetValue(keyValue, @default);
                if (result == node)
                {
                    context.Write(Severity.Error, key, "The specified property does not exist.");
                }
                if (result is LNode)
                {
                    return((LNode)result);
                }
                else
                {
                    return(LNode.Literal(result, node));
                }
            }
            context.Write(Severity.Error, node, "Expected one argument, a key literal, with the default code as an optional second argument.");
            return(null);
        }
Пример #4
0
        /// <summary>Converts <see cref="ILNode"/> to <see cref="LNode"/> recursively.</summary>
        public static LNode ToLNode(this ILNode node)
        {
            if (node is LNode n)
            {
                return(n);
            }

            var attrs = LNodeList.Empty;

            for (int i = node.Min; i < -1; i++)
            {
                attrs.Add(ToLNode(node[i]));
            }

            switch (node.Kind)
            {
            case LNodeKind.Id:
                return(LNode.Id(attrs, node.Name, new SourceRange(node.Range), node.Style));

            case LNodeKind.Literal:
                return(LNode.Literal(attrs, node.Value, new SourceRange(node.Range), node.Style));

            default:
                var args = LNodeList.Empty;
                for (int i = 0, max = node.Max; i <= max; i++)
                {
                    args.Add(ToLNode(node[i]));
                }
                var target = ToLNode(node.Target);
                return(LNode.Call(attrs, target, args, new SourceRange(node.Range), node.Style));
            }
        }
Пример #5
0
        public static LNode _set(LNode node, IMacroContext context)
        {
            var  lhs       = node.Args[0, LNode.Missing];
            var  name      = lhs.Name;
            bool isSnippet = name == _hash_snippet;

            if ((isSnippet || name == _hash_set) && node.ArgCount == 2 && lhs.IsId)
            {
                Symbol newTarget = isSnippet ? _hash_setScopedPropertyQuote : _hash_setScopedProperty;
                var    stmts     = node.Args.Slice(1).Select(key =>
                {
                    LNode value = F.@true;
                    if (key.Calls(S.Assign, 2))
                    {
                        value = key.Args[1];
                        value = context.PreProcess(value);
                        key   = key.Args[0];
                        if (isSnippet && value.Calls(S.Braces))
                        {
                            value = value.Args.AsLNode(S.Splice);
                        }
                    }

                    if (!key.IsId)
                    {
                        context.Write(Severity.Error, key, "Invalid key; expected an identifier.");
                    }
                    return((LNode)node.With(newTarget, LNode.Literal(key.Name, key), value));
                });
                return(F.Call(S.Splice, stmts));
            }
            return(null);
        }
Пример #6
0
        public static LNode ArrayLiteral(LNode node, IMacroContext context)
        {
            var value = node.Value;

            if (value is Array array)
            {
                Type   elementType     = value.GetType().GetElementType();
                string elementTypeName = elementType.NameWithGenericArgs();
                LNode  elementTypeN    = LNode.Call(S.CsRawText, LNode.List(LNode.Literal(elementTypeName)));

                Func <object, LNode, LNode> newLiteral = (el, pnode) => LNode.Literal(el, pnode);
                // Reduce output text size by preventing the printer from using casts
                // e.g. print `23` instead of `(byte) 23` or `(short) 23`. Also, unbox
                // ints to save memory (ideally we'd do this for all Value Types)
                if (elementType == typeof(byte))
                {
                    newLiteral = (el, pnode) => LNode.Literal((int)(byte)el, pnode);
                }
                if (elementType == typeof(sbyte))
                {
                    newLiteral = (el, pnode) => LNode.Literal((int)(sbyte)el, pnode);
                }
                if (elementType == typeof(short))
                {
                    newLiteral = (el, pnode) => LNode.Literal((int)(short)el, pnode);
                }
                if (elementType == typeof(ushort))
                {
                    newLiteral = (el, pnode) => LNode.Literal((int)(ushort)el, pnode);
                }
                if (elementType == typeof(int))
                {
                    newLiteral = (el, pnode) => LNode.Literal((int)(int)el, pnode);
                }

                if (array.Rank == 1)
                {
                    var initializers = new List <LNode>();
                    int count        = 0;
                    foreach (object element in array)
                    {
                        LNode elemNode = newLiteral(element, node);
                        if ((count++ & 7) == 0 && array.Length > 8)
                        {
                            elemNode = elemNode.PlusAttr(LNode.Id(S.TriviaNewline));
                        }
                        initializers.Add(elemNode);
                    }
                    return(LNode.Call(CodeSymbols.New, LNode.List().Add(LNode.Call(LNode.Call(CodeSymbols.Of, LNode.List(LNode.Id(CodeSymbols.Array), elementTypeN)))).AddRange(initializers)));
                }
                else
                {
                    return(null);                       // TODO
                    //Stmt("int[,] Foo = new[,] { {\n 0 }, {\n 1,\n 2, }, };", F.Call(S.Var, F.Of(S.TwoDimensionalArray, S.Int32),
                    //	F.Call(S.Assign, Foo, F.Call(S.New, F.Call(S.TwoDimensionalArray), F.Braces(zero), F.Braces(one, two)))));
                }
            }
            return(null);
        }
Пример #7
0
 private static LNode TranslateLiteral(LNode node, IMessageSink sink, object literal)
 {
     if (!node.IsId)
     {
         return(null);
     }
     return(LNode.Literal(literal, node));
 }
Пример #8
0
 public static LNode overrideTarget(LNode outerNode, IMacroContext context1)
 {
     // Test the indirect way to register a macro
     return(LNode.Call((Symbol)"#registerMacro", LNode.List(LNode.Literal(
                                                                new MacroInfo(null, outerNode[0].Name.Name,
                                                                              (node, context2) =>
     {
         return node.WithTarget(outerNode[1]);
     })
     {
         Mode = MacroMode.PriorityOverride                                 // needed by the unit test
     }))));
 }
Пример #9
0
        public void TestTwoDimensionalArrayLiterals()
        {
            var lemp = NewLemp(10, null);

            Test(LNode.Literal(new String[, ] {
                { "hello" }, { "!" }
            }),
                 lemp, "new String[,] { { \"hello\" }, { \"!\" } };", EcsLanguageService.Value);
            Test(LNode.Literal(new byte[, ] {
                { 1, 2, 3 }, { 4, 5, 6 }, { 7, 8, 9 }, { 254, 255, 0 }
            }),
                 lemp, "new byte[,] { { 1, 2, 3 }, { 4, 5, 6 }, { 7, 8, 9 }, { 254, 255, 0 } };",
                 EcsLanguageService.Value);
        }
Пример #10
0
        public void TestCustomPrinters()
        {
            var lht = new LiteralHandlerTable();

            // Can't add printer for null
            Assert.IsFalse(lht.AddPrinter(true, (Type)null, PrintTrim));
            Assert.IsFalse(lht.AddPrinter(true, (Symbol)null, PrintTrim));

            // Add printer for "trim" marker and string
            Assert.IsTrue(lht.AddPrinter(false, (Symbol)"trim", PrintTrim));
            Assert.IsTrue(lht.AddPrinter(false, typeof(string), PrintTrim));
            Assert.IsFalse(lht.AddPrinter(false, typeof(string), PrintTrim));
            Assert.IsTrue(lht.AddPrinter(true, typeof(string), PrintTrim));
            Assert.IsTrue(lht.AddPrinter(true, typeof(string), PrintTrim));

            // Originally there is no printer for int
            var sb = new StringBuilder();

            Assert.IsTrue(lht.TryPrint(LNode.Literal(123), sb).Right.HasValue);
            Assert.IsTrue(lht.TryPrint(LNode.Literal(123), sb).Right.Value.Format.Contains("no printer for type 'System.Int32'"));
            Assert.AreEqual("", sb.ToString());

            // Add a printer for int and try it
            Assert.IsTrue(lht.AddPrinter(false, typeof(int), PrintTrim));
            Assert.AreEqual("hovercraft", lht.TryPrint(CL(123, "fail"), sb).Left.Value.Name);
            Assert.AreEqual("123", sb.ToString());

            // Add printer for "fail" marker and try it.
            Assert.IsTrue(lht.AddPrinter(false, (Symbol)"fail", PrintFail));
            Assert.AreEqual("Always fails", lht.TryPrint(CL(new int[5], "fail"), sb).Right.Value.Format);
            Assert.AreEqual("FAIL", sb.ToString());

            // TypeMarker printers take priority, so "fail" runs at first. Then the handler for int runs.
            Assert.AreEqual("hovercraft", lht.TryPrint(CL(999, "fail"), sb).Left.Value.Name);
            Assert.AreEqual("999", sb.ToString());

            // Try our string and trim modes
            Assert.AreEqual("hovercraft", lht.TryPrint(LNode.Literal(" hi! "), sb).Left.Value.Name);
            Assert.AreEqual("hi!", sb.ToString());
            Assert.AreEqual("hovercraft", lht.TryPrint(CL(new StringBuilder(" bye! "), "trim"), sb).Left.Value.Name);
            Assert.AreEqual("bye!", sb.ToString());

            // TypeMarker printers take priority, so "firstChar" runs in preference to the string handler.
            Assert.IsTrue(lht.AddPrinter(false, (Symbol)"firstChar", PrintFirstChar));
            Assert.AreEqual("eels", lht.TryPrint(CL("hi!  ", "firstChar"), sb).Left.Value.Name);
            Assert.AreEqual("h", sb.ToString());
        }
Пример #11
0
        public static CalculatorCore New(LNode expr, Dictionary <Symbol, LNode> vars, CalcRange xRange, CalcRange yRange)
        {
            // Find out if the expression uses the variable "y" (or is an equation with '=' or '==')
            // As an (unnecessary) side effect, this throws if an unreferenced var is used
            bool isEquation = expr.Calls(CodeSymbols.Assign, 2) || expr.Calls(CodeSymbols.Eq, 2), usesY = false;

            if (!isEquation)
            {
                LNode zero = LNode.Literal((double)0);
                Func <Symbol, double> lookup = null;
                lookup = name => name == sy_x || (usesY |= name == sy_y) ? 0 : Eval(vars[name], lookup);
                Eval(expr, lookup);
            }
            if (isEquation || usesY)
            {
                return(new Calculator3D(expr, vars, xRange, yRange));
            }
            else
            {
                return(new Calculator2D(expr, vars, xRange));
            }
        }
Пример #12
0
        public void TestOneDimensionalArrayLiterals()
        {
            var lemp = NewLemp(10, null);

            Test(LNode.Literal(new Int32[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }),
                 lemp, "new Int32[] { 1, 2, 3, 4, 5, 6, 7, 8,\n 9, 10 };", EcsLanguageService.Value);
            Test(LNode.Literal(new Int32[] { }),
                 lemp, "new Int32[] { };", EcsLanguageService.Value);
            Test(LNode.Literal(new SByte[] { -1, 2, 3, 4 }),
                 lemp, "new SByte[] { -1, 2, 3, 4 };", EcsLanguageService.Value);
            Test(LNode.Literal(new Byte[] { 0, 255 }),
                 lemp, "new Byte[] { 0, 255 };", EcsLanguageService.Value);
            Test(LNode.Literal(new Int16[] { -32768, 0, 32767 }),
                 lemp, "new Int16[] { -32768, 0, 32767 };", EcsLanguageService.Value);
            Test(LNode.Literal(new Int16[] { -0x8000, 0x0, 0x7FFF }).SetBaseStyle(NodeStyle.HexLiteral),
                 lemp, "new Int16[] { -0x8000, 0x0, 0x7FFF };", EcsLanguageService.Value);
            Test(LNode.Literal(new UInt16[] { 0, 1, 2, 3, 65535 }),
                 lemp, "new UInt16[] { 0, 1, 2, 3, 65535 };", EcsLanguageService.Value);
            Test(LNode.Literal(new String[] { "hello", "!" }),
                 lemp, "new String[] { \"hello\", \"!\" };", EcsLanguageService.Value);
            Test(LNode.Literal(new String[][] { new String[] { "hello" }, new String[] { "!" } }),
                 lemp, "new String[][] { new String[] { \"hello\" }, new String[] { \"!\" } };", EcsLanguageService.Value);
        }
Пример #13
0
            private void MakeArgListTests(VList <LNode> patternArgs, ref LNode candidate)
            {
                Symbol varArgSym  = null;
                LNode  varArgCond = null;
                int    i;

                for (i = 0; i < patternArgs.Count; i++)
                {
                    MakeTestExpr(patternArgs[i], LNode.Call(CodeSymbols.IndexBracks, LNode.List(LNode.Call(CodeSymbols.Dot, LNode.List(candidate, LNode.Id((Symbol)"Args"))), F.Literal(i))), out varArgSym, out varArgCond);
                    if (varArgSym != null)
                    {
                        break;
                    }
                }
                int i2 = i + 1;

                for (int left = patternArgs.Count - i2; i2 < patternArgs.Count; i2++)
                {
                    Symbol varArgSym2  = null;
                    LNode  varArgCond2 = null;
                    MakeTestExpr(patternArgs[i2], LNode.Call(CodeSymbols.IndexBracks, LNode.List(LNode.Call(CodeSymbols.Dot, LNode.List(candidate, LNode.Id((Symbol)"Args"))), LNode.Call(CodeSymbols.Sub, LNode.List(LNode.Call(CodeSymbols.Dot, LNode.List(LNode.Call(CodeSymbols.Dot, LNode.List(candidate, LNode.Id((Symbol)"Args"))), LNode.Id((Symbol)"Count"))), F.Literal(left))).SetStyle(NodeStyle.Operator))), out varArgSym2, out varArgCond2);
                    if (varArgSym2 != null)
                    {
                        Context.Sink.Write(Severity.Error, patternArgs[i2], "More than a single $(...varargs) variable is not supported in a single argument list.");
                        break;
                    }
                    left--;
                }
                if (varArgSym != null && (varArgSym != __ || varArgCond != null))
                {
                    LNode varArgSymId = F.Id(varArgSym);
                    LNode grabVarArgs;
                    if (i == 0 && patternArgs.Count == 1)
                    {
                        grabVarArgs = LNode.Call(CodeSymbols.Assign, LNode.List(varArgSymId, LNode.Call(CodeSymbols.Dot, LNode.List(candidate, LNode.Id((Symbol)"Args"))))).SetStyle(NodeStyle.Operator);
                    }
                    else if (i == 0 && patternArgs.Count > 1)
                    {
                        var fixedArgsLit = F.Literal(patternArgs.Count - 1);
                        grabVarArgs = LNode.Call(CodeSymbols.Assign, LNode.List(varArgSymId, LNode.Call(LNode.Call(CodeSymbols.Dot, LNode.List(LNode.Call(CodeSymbols.Dot, LNode.List(candidate, LNode.Id((Symbol)"Args"))), LNode.Id((Symbol)"WithoutLast"))), LNode.List(fixedArgsLit)))).SetStyle(NodeStyle.Operator);
                    }
                    else
                    {
                        var varArgStartLit = F.Literal(i);
                        var fixedArgsLit   = F.Literal(patternArgs.Count - 1);
                        if (i + 1 == patternArgs.Count)
                        {
                            grabVarArgs = LNode.Call(CodeSymbols.Assign, LNode.List(varArgSymId, LNode.Call(CodeSymbols.New, LNode.List(LNode.Call(LNode.Call(CodeSymbols.Of, LNode.List(LNode.Id((Symbol)"VList"), LNode.Id((Symbol)"LNode"))), LNode.List(LNode.Call(LNode.Call(CodeSymbols.Dot, LNode.List(LNode.Call(CodeSymbols.Dot, LNode.List(candidate, LNode.Id((Symbol)"Args"))), LNode.Id((Symbol)"Slice"))), LNode.List(varArgStartLit)))))))).SetStyle(NodeStyle.Operator);
                        }
                        else
                        {
                            grabVarArgs = LNode.Call(CodeSymbols.Assign, LNode.List(varArgSymId, LNode.Call(CodeSymbols.New, LNode.List(LNode.Call(LNode.Call(CodeSymbols.Of, LNode.List(LNode.Id((Symbol)"VList"), LNode.Id((Symbol)"LNode"))), LNode.List(LNode.Call(LNode.Call(CodeSymbols.Dot, LNode.List(LNode.Call(CodeSymbols.Dot, LNode.List(candidate, LNode.Id((Symbol)"Args"))), LNode.Id((Symbol)"Slice"))), LNode.List(varArgStartLit, LNode.Call(CodeSymbols.Sub, LNode.List(LNode.Call(CodeSymbols.Dot, LNode.List(LNode.Call(CodeSymbols.Dot, LNode.List(candidate, LNode.Id((Symbol)"Args"))), LNode.Id((Symbol)"Count"))), fixedArgsLit)).SetStyle(NodeStyle.Operator))))))))).SetStyle(NodeStyle.Operator);
                        }
                    }
                    if (varArgCond != null || IsMultiCase)
                    {
                        Tests.Add(LNode.Call(CodeSymbols.OrBits, LNode.List(LNode.Call(CodeSymbols.Dot, LNode.List(grabVarArgs.PlusAttrs(LNode.List(LNode.InParensTrivia)), LNode.Id((Symbol)"IsEmpty"))), LNode.Literal(true))).SetStyle(NodeStyle.Operator));
                        Tests.Add(varArgCond);
                    }
                    else
                    {
                        ThenClause.Add(grabVarArgs);
                    }
                }
            }
Пример #14
0
 [LexicalMacro("match (var) { case ...: ... }; // In LES, use a => b instead of case a: b", "Attempts to match and deconstruct an object against a \"pattern\", such as a tuple or an algebraic data type. Example:\n" + "match (obj) {  \n" + "   case is Shape(ShapeType.Circle, $size, Location: $p is Point<int>($x, $y)): \n" + "      Circle(size, x, y); \n" + "}\n\n" + "This is translated to the following C# code: \n" + "do { \n" + "   Point<int> p; \n" + "   Shape tmp1; \n" + "   if (obj is Shape) { \n" + "      var tmp1 = (Shape)obj; \n" + "      if (tmp1.Item1 == ShapeType.Circle) { \n" + "         var size = tmp1.Item2; \n" + "         var tmp2 = tmp1.Location; \n" + "         if (tmp2 is Point<int>) { \n" + "            var p = (Point<int>)tmp2; \n" + "            var x = p.Item1; \n" + "            var y = p.Item2; \n" + "            Circle(size, x, y); \n" + "            break; \n" + "         } \n" + "      }\n" + "   }\n" + "} while(false); \n" + "`break` is not expected at the end of each handler (`case` code block), but it can " + "be used to exit early from a `case`. You can associate multiple patterns with the same " + "handler using `case pattern1, pattern2:` in EC#, but please note that (due to a " + "limitation of plain C#) this causes code duplication since the handler will be repeated " + "for each pattern.")] public static LNode match(LNode node, IMacroContext context)
 {
     {
         LNode         input;
         VList <LNode> contents;
         if (node.Args.Count == 2 && (input = node.Args[0]) != null && node.Args[1].Calls(CodeSymbols.Braces))
         {
             contents = node.Args[1].Args;
             var outputs = new WList <LNode>();
             input = MaybeAddTempVarDecl(input, outputs);
             int next_i = 0;
             for (int case_i = 0; case_i < contents.Count; case_i = next_i)
             {
                 var @case = contents[case_i];
                 if (!IsCaseLabel(@case))
                 {
                     return(Reject(context, contents[0], "In 'match': expected 'case' statement"));
                 }
                 for (next_i = case_i + 1; next_i < contents.Count; next_i++)
                 {
                     var stmt = contents[next_i];
                     if (IsCaseLabel(stmt))
                     {
                         break;
                     }
                     if (stmt.Calls(S.Break, 0))
                     {
                         next_i++;
                         break;
                     }
                 }
                 var handler = new VList <LNode>(contents.Slice(case_i + 1, next_i - (case_i + 1)));
                 if (@case.Calls(S.Case) && @case.Args.Count > 0)
                 {
                     var codeGen = new CodeGeneratorForMatchCase(context, input, handler);
                     foreach (var pattern in @case.Args)
                     {
                         outputs.Add(codeGen.GenCodeForPattern(pattern));
                     }
                 }
                 else
                 {
                     outputs.Add(LNode.Call(CodeSymbols.Braces, LNode.List(handler)).SetStyle(NodeStyle.Statement));
                     if (next_i < contents.Count)
                     {
                         context.Write(Severity.Error, contents[next_i], "The default branch must be the final branch in a 'match' statement.");
                     }
                 }
             }
             return(LNode.Call(CodeSymbols.DoWhile, LNode.List(outputs.ToVList().AsLNode(S.Braces), LNode.Literal(false))));
         }
     }
     return(null);
 }
Пример #15
0
            void GenCodeForPattern(LNode input, LNode pattern)
            {
                bool          refExistingVar;
                LNode         varBinding, cmpExpr, isType, inRange;
                VList <LNode> subPatterns, conditions;

                GetPatternComponents(pattern, out varBinding, out refExistingVar, out cmpExpr, out isType, out inRange, out subPatterns, out conditions);
                if (isType != null)
                {
                    if ((cmpExpr ?? inRange ?? varBinding) != null)
                    {
                        if (!LooksLikeSimpleValue(input))
                        {
                            PutStmt(TempVarDecl(input, out input));
                        }
                    }
                    PutCond(LNode.Call(CodeSymbols.Is, LNode.List(input, isType)).SetStyle(NodeStyle.Operator));
                    if (varBinding == null && ((cmpExpr ?? inRange) != null || subPatterns.Count > 0))
                    {
                        varBinding = LNode.Id(NextTempName(), isType);
                    }
                }
                if (varBinding != null)
                {
                    if (isType != null)
                    {
                        if (refExistingVar)
                        {
                            PutStmt(LNode.Call(CodeSymbols.Assign, LNode.List(varBinding, LNode.Call(CodeSymbols.Cast, LNode.List(input, isType)).SetStyle(NodeStyle.Operator))).SetStyle(NodeStyle.Operator));
                        }
                        else
                        {
                            PutStmt(LNode.Call(CodeSymbols.Var, LNode.List(isType, LNode.Call(CodeSymbols.Assign, LNode.List(varBinding, LNode.Call(CodeSymbols.Cast, LNode.List(input, isType)).SetStyle(NodeStyle.Operator))))));
                        }
                    }
                    else
                    {
                        if (refExistingVar)
                        {
                            PutStmt(LNode.Call(CodeSymbols.Assign, LNode.List(varBinding, input)).SetStyle(NodeStyle.Operator));
                        }
                        else
                        {
                            PutStmt(LNode.Call(CodeSymbols.Var, LNode.List(LNode.Missing, LNode.Call(CodeSymbols.Assign, LNode.List(varBinding, input)))));
                        }
                    }
                    input = varBinding;
                }
                if (cmpExpr != null)
                {
                    if (cmpExpr.Value == null)
                    {
                        PutCond(LNode.Call(CodeSymbols.Eq, LNode.List(input, LNode.Literal(null))).SetStyle(NodeStyle.Operator));
                    }
                    else
                    {
                        PutCond(LNode.Call(LNode.Call(CodeSymbols.Dot, LNode.List(cmpExpr, LNode.Id((Symbol)"Equals"))), LNode.List(input)));
                    }
                }
                for (int itemIndex = 0; itemIndex < subPatterns.Count; itemIndex++)
                {
                    var   subPattern = subPatterns[itemIndex];
                    LNode propName;
                    if (subPattern.Calls(S.NamedArg, 2) || subPattern.Calls(S.Colon, 2))
                    {
                        propName   = subPattern[0];
                        subPattern = subPattern[1];
                    }
                    else
                    {
                        propName = LNode.Id("Item" + (itemIndex + 1), subPattern);
                    }
                    GenCodeForPattern(LNode.Call(CodeSymbols.Dot, LNode.List(input, propName)), subPattern);
                }
                if (inRange != null)
                {
                    PutCond(LNode.Call(CodeSymbols.In, LNode.List(input, inRange)).SetStyle(NodeStyle.Operator));
                }
                foreach (var cond in conditions)
                {
                    PutCond(cond);
                }
            }
Пример #16
0
        public static LNode match(LNode node, IMacroContext context)
        {
            {
                LNode         input;
                VList <LNode> contents;
                if (node.Args.Count == 2 && (input = node.Args[0]) != null && node.Args[1].Calls(CodeSymbols.Braces))
                {
                    contents = node.Args[1].Args;
                    var outputs = new WList <LNode>();
                    input = MaybeAddTempVarDecl(context, input, outputs);

                    // Process the braced block, one case at a time
                    int next_i = 0;
                    for (int case_i = 0; case_i < contents.Count; case_i = next_i)
                    {
                        var @case = contents[case_i];
                        if (!IsCaseLabel(@case)                         // `case ...:` or `default:`
                            )
                        {
                            return(Reject(context, contents[0], "In 'match': expected 'case' statement"));
                        }
                        // Find the end of the current case/default block
                        for (next_i = case_i + 1; next_i < contents.Count; next_i++)
                        {
                            var stmt = contents[next_i];
                            if (IsCaseLabel(stmt))
                            {
                                break;
                            }
                            if (stmt.Calls(S.Break, 0))
                            {
                                next_i++;
                                break;
                            }
                        }
                        //  handler: the list of statements underneath `case`
                        var handler = new VList <LNode>(contents.Slice(case_i + 1, next_i - (case_i + 1)));

                        if (@case.Calls(S.Case) && @case.Args.Count > 0)
                        {
                            var codeGen = new CodeGeneratorForMatchCase(context, input, handler);
                            foreach (var pattern in @case.Args)
                            {
                                outputs.Add(codeGen.GenCodeForPattern(pattern));
                            }
                        }
                        else                                    // default:
                        // Note: the extra {braces} around the handler are rarely
                        // needed. They are added just in case the handler declares a
                        // variable and a different handler declares another variable
                        // by the same name, which is illegal unless we add braces.
                        {
                            outputs.Add(LNode.Call(CodeSymbols.Braces, LNode.List(handler)).SetStyle(NodeStyle.Statement));
                            if (next_i < contents.Count)
                            {
                                context.Sink.Error(contents[next_i], "The default branch must be the final branch in a 'match' statement.");
                            }
                        }
                    }
                    return(LNode.Call(CodeSymbols.DoWhile, LNode.List(outputs.ToVList().AsLNode(S.Braces), LNode.Literal(false))));
                }
            }
            return(null);
        }
Пример #17
0
            void ProcessAttribute(LNode attr, Symbol mode, LNode exceptionType, LNode variableName, bool isPropSetter)
            {
                var    conditions     = attr.Args;
                object haveCCRewriter = Context.ScopedProperties.TryGetValue(_haveContractRewriter, null);

                _haveCCRewriter = haveCCRewriter is bool?(bool)haveCCRewriter : false;

                // #notnull is equivalent to either requires(_ != null) or ensures(_ != null)
                if (mode == sy_notnull)
                {
                    if (attr.Args.Count != 0)
                    {
                        Context.Sink.Warning(attr, "'#notnull' does not expect arguments.");
                    }
                    if (variableName != null                            // argument
                        )
                    {
                        mode = sy_requires;
                    }
                    else
                    {
                        // return value
                        mode = sy_ensures;
                    }
                    conditions.Add(LNode.Call(CodeSymbols.Neq, LNode.List(LNode.Id((Symbol)"_"), LNode.Literal(null))).SetStyle(NodeStyle.Operator));
                }
                else if (!attr.IsCall)
                {
                    Context.Sink.Warning(attr, "'{0}' expects a list of conditions.", attr.Name);
                }

                if (mode == sy_requires || mode == sy_assert)
                {
                    ProcessRequiresAttribute(conditions, mode, variableName);
                }
                else                    // mode == @@ensures || mode == @@ensuresFinally || mode == @@ensuresOnThrow
                {
                    if (variableName != null && !isPropSetter)
                    {
                        Context.Sink.Error(attr, "The '{0}' attribute does not apply to method arguments.", mode);
                    }
                    else
                    {
                        ProcessEnsuresAttribute(conditions, mode, exceptionType, variableName);
                    }
                }
            }
Пример #18
0
            private void MatchAttributes(LNode pattern, LNode candidate)
            {
                LNode  condition;
                bool   isParams, refExistingVar;
                Symbol listVar;
                var    pAttrs = pattern.PAttrs();

                if (pAttrs.Count == 1 && (listVar = DecodeSubstitutionExpr(pAttrs[0], out condition, out isParams, out refExistingVar)) != null && isParams)
                {
                    if (listVar != __ || condition != null)
                    {
                        if (!refExistingVar)
                        {
                            AddVar(listVar, true, errAt: pattern);
                        }
                        Tests.Add(LNode.Call(CodeSymbols.OrBits, LNode.List(LNode.Call(CodeSymbols.Dot, LNode.List(LNode.Call(LNode.List(LNode.InParensTrivia), CodeSymbols.Assign, LNode.List(F.Id(listVar), LNode.Call(CodeSymbols.Dot, LNode.List(candidate, LNode.Id((Symbol)"Attrs"))).SetStyle(NodeStyle.Operator))).SetStyle(NodeStyle.Operator), LNode.Id((Symbol)"IsEmpty"))).SetStyle(NodeStyle.Operator), LNode.Literal(true))).SetStyle(NodeStyle.Operator));
                        if (condition != null)
                        {
                            Tests.Add(condition);
                        }
                    }
                }
                else if (pAttrs.Count != 0)
                {
                    Context.Sink.Error(pAttrs[0], "Currently, Attribute matching is very limited; you can only use `[$(...varName)]`");
                }
            }
Пример #19
0
        public static LNode CompileMacro(LNode pattern, LNode body, IMacroContext context, LNodeList attrs)
        {
            var modeNodes = attrs.Where(a => Enum.TryParse(a.Name.Name, out MacroMode _));
            // unwrap braces (they're not part of the pattern, they just enable statement syntax in EC#)
            var       pattern_apos = pattern.UnwrapBraces();
            MacroMode modes        = GetMacroMode(ref attrs, pattern_apos);

            // compileTime {...} can recognize macro method definitions.
            // Take advantage of this by generating a macro method which it will register for us.
            LNode macroName   = pattern_apos.Target ?? pattern_apos;
            LNode syntax      = F.Literal(pattern_apos.ToString());
            LNode description = attrs.FirstOrDefault(a => a.Value is string) ?? F.Literal("User-defined macro at {0}".Localized(pattern.Range.Start));

            attrs = attrs.SmartWhere(a => !(a.Value is string));                // remove docstring, if any
            var extraArgs = LNode.List();

            if (macroName.IsId)
            {
                extraArgs.Add(F.Literal(macroName.Name.Name));
            }
            else
            {
                Debug.Assert((modes & (MacroMode.MatchEveryCall | MacroMode.MatchEveryIdentifier | MacroMode.MatchEveryLiteral)) != 0);
            }

            // ensure operator macros like `'+` are not printed as `operator+` which C# will reject
            if (EcsValidators.IsOperator(macroName.Name))
            {
                macroName = F.Id(EcsValidators.SanitizeIdentifier(macroName.Name.Name));
            }

            LNode modesExpr = null;

            foreach (LNode mode in modeNodes)
            {
                modesExpr = LNode.MergeBinary(modesExpr, LNode.Call(CodeSymbols.Dot, LNode.List(LNode.Call(CodeSymbols.Dot, LNode.List(LNode.Call(CodeSymbols.ColonColon, LNode.List(LNode.Id((Symbol)"global"), LNode.Id((Symbol)"LeMP"))).SetStyle(NodeStyle.Operator), LNode.Id((Symbol)"MacroMode"))).SetStyle(NodeStyle.Operator), mode)).SetStyle(NodeStyle.Operator), S.OrBits);
            }
            if (modesExpr != null)
            {
                extraArgs.Add(LNode.Call(CodeSymbols.Assign, LNode.List(LNode.Id((Symbol)"Mode"), modesExpr)).SetStyle(NodeStyle.Operator));
            }

            LNode lmAttribute = LNode.Call(LNode.Call(CodeSymbols.Dot, LNode.List(LNode.Call(CodeSymbols.ColonColon, LNode.List(LNode.Id((Symbol)"global"), LNode.Id((Symbol)"LeMP"))).SetStyle(NodeStyle.Operator), LNode.Id((Symbol)"LexicalMacroAttribute"))).SetStyle(NodeStyle.Operator), LNode.List().Add(syntax).Add(description).AddRange(extraArgs));

            if (!body.Calls(S.Braces))
            {
                body = LNode.Call(CodeSymbols.Braces, LNode.List(LNode.Call(CodeSymbols.Return, LNode.List(body)))).SetStyle(NodeStyle.StatementBlock);
            }

            body = context.PreProcess(body);

            // Look for "using" statements above the macro() call
            LNodeList usingDirectives = LNode.List(context.PreviousSiblings.Where(n => n.Calls(S.Import)));

            // Look for "using" and "#r" statements at the beginning of the body
            if (body.Calls(S.Braces))
            {
                var bodyUsings = body.Args.TakeNowWhile(stmt => stmt.Calls(S.Import) || stmt.Calls(S.CsiReference));
                usingDirectives.AddRange(bodyUsings);
                body = body.WithArgs(body.Args.Slice(bodyUsings.Count));
            }

            // Create a matchCode statement unless the pattern is MacroName($(.._)), which always matches
            if (!(pattern_apos.HasSimpleHeadWithoutPAttrs() && pattern_apos.Target.IsId &&
                  pattern_apos.ArgCount == 1 && pattern_apos[0].Equals(LNode.Call(CodeSymbols.Substitute, LNode.List(LNode.Call(CodeSymbols.DotDot, LNode.List(LNode.Id((Symbol)"_"))).SetStyle(NodeStyle.Operator))).SetStyle(NodeStyle.Operator))))
            {
                // Note: the body is already preprocessed; #noLexicalMacros prevents double-processing
                body = LNode.Call(CodeSymbols.Braces, LNode.List(LNode.Call((Symbol)"matchCode", LNode.List(LNode.Id((Symbol)"#node"), LNode.Call(CodeSymbols.Braces, LNode.List(LNode.Call(CodeSymbols.Case, LNode.List(pattern)), LNode.Call((Symbol)"#noLexicalMacros", LNode.List(body.AsList(S.Braces))))).SetStyle(NodeStyle.StatementBlock))).SetStyle(NodeStyle.Special), LNode.Call(CodeSymbols.Return, LNode.List(LNode.Literal(null))))).SetStyle(NodeStyle.StatementBlock);
            }

            return(LNode.Call((Symbol)"compileTime", LNode.List(LNode.Call(CodeSymbols.Braces, LNode.List().AddRange(usingDirectives).Add(LNode.Call(LNode.List().Add(lmAttribute).AddRange(attrs).Add(LNode.Id(CodeSymbols.Public)).Add(LNode.Id(CodeSymbols.Static)), CodeSymbols.Fn, LNode.List(LNode.Id((Symbol)"LNode"), macroName, LNode.Call(CodeSymbols.AltList, LNode.List(LNode.Call(CodeSymbols.Var, LNode.List(LNode.Id((Symbol)"LNode"), LNode.Id((Symbol)"#node"))), LNode.Call(CodeSymbols.Var, LNode.List(LNode.Call(CodeSymbols.Dot, LNode.List(LNode.Call(CodeSymbols.ColonColon, LNode.List(LNode.Id((Symbol)"global"), LNode.Id((Symbol)"LeMP"))).SetStyle(NodeStyle.Operator), LNode.Id((Symbol)"IMacroContext"))).SetStyle(NodeStyle.Operator), LNode.Id((Symbol)"#context"))))), body)))).SetStyle(NodeStyle.StatementBlock))).SetStyle(NodeStyle.Special));
        }
Пример #20
0
 public static string PrintLiteral(object value, NodeStyle style = 0) => PrintLiteral(LNode.Literal(value, null, style));
Пример #21
0
            private void MakeTestExpr(LNode pattern, LNode candidate, out Symbol varArgSym, out LNode varArgCond)
            {
                varArgSym = null; varArgCond = null;

                // is this a $substitutionVar?
                LNode condition;
                bool  isParams, refExistingVar;
                var   nodeVar = DecodeSubstitutionExpr(pattern, out condition, out isParams, out refExistingVar);

                // Unless the candidate is a simple variable name, avoid repeating
                // it by creating a temporary variable to hold its value
                int predictedTests = pattern.Attrs.Count +
                                     (nodeVar != null ? 0 : pattern.Args.Count) +
                                     (!pattern.HasSimpleHeadWithoutPAttrs() ? 1 : 0);

                if (predictedTests > 1)
                {
                    candidate = MaybePutCandidateInTempVar(candidate.IsCall, candidate);
                }

                MatchAttributes(pattern, candidate);                    // Look for @[$(...var)]
                // case $_
                if (nodeVar != null)
                {
                    if (nodeVar != __ || condition != null)
                    {
                        if (!refExistingVar)
                        {
                            AddVar(nodeVar, isParams, errAt: pattern);
                        }
                        if (!isParams)
                        {
                            var assignment = LNode.Call(CodeSymbols.Assign, LNode.List(F.Id(nodeVar), candidate)).SetStyle(NodeStyle.Operator);
                            Tests.Add(LNode.Call(CodeSymbols.NotEq, LNode.List(assignment.PlusAttrs(LNode.List(LNode.InParensTrivia)), LNode.Literal(null))).SetStyle(NodeStyle.Operator));
                            Tests.Add(condition);
                        }
                    }
                    if (isParams)
                    {
                        varArgSym  = nodeVar;
                        varArgCond = condition;
                        return;
                    }
                }
                else if (pattern.IsId)
                {
                    Tests.Add(LNode.Call(LNode.Call(CodeSymbols.Dot, LNode.List(candidate, LNode.Id((Symbol)"IsIdNamed"))).SetStyle(NodeStyle.Operator), LNode.List(LNode.Call(CodeSymbols.Cast, LNode.List(F.Literal(pattern.Name.Name), LNode.Id((Symbol)"Symbol"))).SetStyle(NodeStyle.Operator))));
                }
                else if (pattern.IsLiteral)
                {
                    if (pattern.Value == null)
                    {
                        Tests.Add(LNode.Call(CodeSymbols.Eq, LNode.List(LNode.Call(CodeSymbols.Dot, LNode.List(candidate, LNode.Id((Symbol)"Value"))).SetStyle(NodeStyle.Operator), LNode.Literal(null))).SetStyle(NodeStyle.Operator));
                    }
                    else
                    {
                        Tests.Add(LNode.Call(LNode.Call(CodeSymbols.Dot, LNode.List(pattern, LNode.Id((Symbol)"Equals"))).SetStyle(NodeStyle.Operator), LNode.List(LNode.Call(CodeSymbols.Dot, LNode.List(candidate, LNode.Id((Symbol)"Value"))).SetStyle(NodeStyle.Operator))));
                    }
                }
                else                            // call(...)
                {
                    int?varArgAt;
                    int fixedArgC = GetFixedArgCount(pattern.Args, out varArgAt);

                    // Test if the call target matches
                    var pTarget = pattern.Target;
                    if (pTarget.IsId && !pTarget.HasPAttrs())
                    {
                        var   quoteTarget = QuoteSymbol(pTarget.Name);
                        LNode targetTest;
                        if (varArgAt.HasValue && fixedArgC == 0)
                        {
                            targetTest = LNode.Call(LNode.Call(CodeSymbols.Dot, LNode.List(candidate, LNode.Id((Symbol)"Calls"))).SetStyle(NodeStyle.Operator), LNode.List(quoteTarget));
                        }
                        else if (varArgAt.HasValue)
                        {
                            targetTest = LNode.Call(LNode.Call(CodeSymbols.Dot, LNode.List(candidate, LNode.Id((Symbol)"CallsMin"))).SetStyle(NodeStyle.Operator), LNode.List(quoteTarget, F.Literal(fixedArgC)));
                        }
                        else
                        {
                            targetTest = LNode.Call(LNode.Call(CodeSymbols.Dot, LNode.List(candidate, LNode.Id((Symbol)"Calls"))).SetStyle(NodeStyle.Operator), LNode.List(quoteTarget, F.Literal(fixedArgC)));
                        }
                        Tests.Add(targetTest);
                    }
                    else
                    {
                        if (fixedArgC == 0)
                        {
                            Tests.Add(LNode.Call(CodeSymbols.Dot, LNode.List(candidate, LNode.Id((Symbol)"IsCall"))).SetStyle(NodeStyle.Operator));
                            if (!varArgAt.HasValue)
                            {
                                Tests.Add(LNode.Call(CodeSymbols.Eq, LNode.List(LNode.Call(CodeSymbols.Dot, LNode.List(LNode.Call(CodeSymbols.Dot, LNode.List(candidate, LNode.Id((Symbol)"Args"))).SetStyle(NodeStyle.Operator), LNode.Id((Symbol)"Count"))).SetStyle(NodeStyle.Operator), LNode.Literal(0))).SetStyle(NodeStyle.Operator));
                            }
                        }
                        else
                        {
                            var op = varArgAt.HasValue ? S.GE : S.Eq;
                            Tests.Add(LNode.Call(op, LNode.List(LNode.Call(CodeSymbols.Dot, LNode.List(LNode.Call(CodeSymbols.Dot, LNode.List(candidate, LNode.Id((Symbol)"Args"))).SetStyle(NodeStyle.Operator), LNode.Id((Symbol)"Count"))).SetStyle(NodeStyle.Operator), F.Literal(fixedArgC))));
                        }
                        int i = Tests.Count;
                        MakeTestExpr(pTarget, LNode.Call(CodeSymbols.Dot, LNode.List(candidate, LNode.Id((Symbol)"Target"))).SetStyle(NodeStyle.Operator));
                    }

                    MakeArgListTests(pattern.Args, ref candidate);
                }
            }
Пример #22
0
            void GenCodeForPattern(LNode input, LNode pattern)
            {
                // Get the parts of the pattern, e.g. `$x is T(sp)` => varBinding=x, isType=T, sp is returned
                bool          refExistingVar;
                LNode         varBinding, cmpExpr, isType, inRange;
                VList <LNode> subPatterns, conditions;

                GetPatternComponents(pattern, out varBinding, out refExistingVar, out cmpExpr, out isType, out inRange, out subPatterns, out conditions);

                // For a pattern like `(varBinding is IsType in A...B)(subPatterns) && conds`,
                // our goal is to generate code like this:
                //
                //   var tmp_1 = $input; // temp var created unless $input looks simple
                //   if (tmp_1 is IsType) {
                //     Type varBinding = (IsType)tmp_1;
                //     if (varBinding >= A && varBinding <= B && /* code for matching subPatterns */)
                //         if (conds)
                //             $handler;
                //   }
                if (isType != null)
                {
                    if ((cmpExpr ?? inRange ?? varBinding) != null)
                    {
                        // input will be used multiple times, so consider making a tmp var.
                        if (!LooksLikeSimpleValue(input))
                        {
                            PutStmt(TempVarDecl(_context, input, out input));
                        }
                    }

                    PutCond(LNode.Call(CodeSymbols.Is, LNode.List(input, isType)).SetStyle(NodeStyle.Operator));

                    if (varBinding == null && ((cmpExpr ?? inRange) != null || subPatterns.Count > 0))
                    {
                        // we'll need another temp variable to hold the same value, casted.
                        varBinding = LNode.Id(NextTempName(_context), isType);
                    }
                }

                if (varBinding != null)
                {
                    if (isType != null)
                    {
                        if (refExistingVar)
                        {
                            PutStmt(LNode.Call(CodeSymbols.Assign, LNode.List(varBinding, LNode.Call(CodeSymbols.Cast, LNode.List(input, isType)).SetStyle(NodeStyle.Operator))).SetStyle(NodeStyle.Operator));
                        }
                        else
                        {
                            PutStmt(LNode.Call(CodeSymbols.Var, LNode.List(isType, LNode.Call(CodeSymbols.Assign, LNode.List(varBinding, LNode.Call(CodeSymbols.Cast, LNode.List(input, isType)).SetStyle(NodeStyle.Operator))))));
                        }
                    }
                    else
                    {
                        if (refExistingVar)
                        {
                            PutStmt(LNode.Call(CodeSymbols.Assign, LNode.List(varBinding, input)).SetStyle(NodeStyle.Operator));
                        }
                        else
                        {
                            PutStmt(LNode.Call(CodeSymbols.Var, LNode.List(LNode.Missing, LNode.Call(CodeSymbols.Assign, LNode.List(varBinding, input)))));
                        }
                    }
                    input = varBinding;
                }

                if (cmpExpr != null)                    // do equality test
                {
                    if (cmpExpr.Value == null)
                    {
                        PutCond(LNode.Call(CodeSymbols.Eq, LNode.List(input, LNode.Literal(null))).SetStyle(NodeStyle.Operator));
                    }
                    else
                    {
                        PutCond(LNode.Call(LNode.Call(CodeSymbols.Dot, LNode.List(cmpExpr, LNode.Id((Symbol)"Equals"))).SetStyle(NodeStyle.Operator), LNode.List(input)));
                    }
                }

                // Generate code for subpatterns
                for (int itemIndex = 0; itemIndex < subPatterns.Count; itemIndex++)
                {
                    var   subPattern = subPatterns[itemIndex];
                    LNode propName;
                    // Recognize `propName:` in front of the subpattern (fun fact: we
                    // can't use `matchCode` to detect a named parameter here, because if
                    // we write `case { $propName: $subPattern; }:` it is parsed as a
                    // goto-label, not as a named parameter.)
                    if (subPattern.Calls(S.NamedArg, 2) || subPattern.Calls(S.Colon, 2))
                    {
                        propName   = subPattern[0];
                        subPattern = subPattern[1];
                    }
                    else
                    {
                        propName = LNode.Id("Item" + (itemIndex + 1), subPattern);
                    }

                    GenCodeForPattern(LNode.Call(CodeSymbols.Dot, LNode.List(input, propName)).SetStyle(NodeStyle.Operator), subPattern);
                }

                if (inRange != null)
                {
                    PutCond(LNode.Call(CodeSymbols.In, LNode.List(input, inRange)).SetStyle(NodeStyle.Operator));
                }

                foreach (var cond in conditions)
                {
                    PutCond(cond);
                }
            }
Пример #23
0
 // Used for optimization, to avoid writing complicated expressions in the output:
 // e.g. instead of  code.Args[0].Target.Args.Count == 1 && code.Args[0].Target.Args[0].IsIdNamed((Symbol) "_")
 //   we might write (tmp_5 = code.Args[0].Target) != null && tmp_5.Args.Count == 1 && tmp_5.Args[0].IsIdNamed((Symbol) "_")
 LNode MaybePutCandidateInTempVar(bool condition, LNode candidate)
 {
     if (condition)
     {
         var targetTmp   = NextTempName(Context);
         var targetTmpId = F.Id(targetTmp);
         AddVar(targetTmp, false, errAt: candidate);
         Tests.Add(LNode.Call(CodeSymbols.NotEq, LNode.List(LNode.Call(LNode.List(LNode.InParensTrivia), CodeSymbols.Assign, LNode.List(targetTmpId, candidate)).SetStyle(NodeStyle.Operator), LNode.Literal(null))).SetStyle(NodeStyle.Operator));
         return(targetTmpId);
     }
     else
     {
         return(candidate);
     }
 }
Пример #24
0
 LNode EliminateSequenceExpressionsInExecStmt(LNode stmt)
 {
     {
         LNode         block, collection, cond, init, initValue, loopVar, name, tmp_11, tmp_12, type;
         VList <LNode> attrs, incs, inits;
         if (stmt.Calls(CodeSymbols.Braces))
         {
             return(stmt.WithArgs(EliminateSequenceExpressions(stmt.Args, false)));
         }
         else if (stmt.CallsMin(CodeSymbols.If, 1) || stmt.Calls(CodeSymbols.UsingStmt, 2) || stmt.Calls(CodeSymbols.Lock, 2) || stmt.Calls(CodeSymbols.Switch, 2) && stmt.Args[1].Calls(CodeSymbols.Braces))
         {
             return(ProcessBlockCallStmt(stmt, 1));
         }
         else if ((attrs = stmt.Attrs).IsEmpty | true && stmt.Calls(CodeSymbols.Fixed, 2) && (init = stmt.Args[0]) != null && (block = stmt.Args[1]) != null)
         {
             init  = EliminateSequenceExpressionsInExecStmt(init);
             block = EliminateSequenceExpressionsInChildStmt(block);
             if (init.CallsMin(__numrunSequence, 1))
             {
                 return(LNode.Call(LNode.List(attrs), CodeSymbols.Braces, LNode.List().AddRange(init.Args.WithoutLast(1)).Add(LNode.Call(CodeSymbols.Fixed, LNode.List(init.Args.Last, block)))).SetStyle(NodeStyle.Statement));
             }
             else
             {
                 return(stmt.WithArgChanged(1, block));
             }
         }
         else if ((attrs = stmt.Attrs).IsEmpty | true && stmt.Calls(CodeSymbols.While, 2) && (cond = stmt.Args[0]) != null && (block = stmt.Args[1]) != null)
         {
             cond  = BubbleUpBlocks(cond);
             block = EliminateSequenceExpressionsInChildStmt(block);
             if (cond.CallsMin(__numrunSequence, 1))
             {
                 return(LNode.Call(LNode.List(attrs), CodeSymbols.For, LNode.List(LNode.Call(CodeSymbols.AltList), LNode.Missing, LNode.Call(CodeSymbols.AltList), LNode.Call(CodeSymbols.Braces, LNode.List().AddRange(cond.Args.WithoutLast(1)).Add(LNode.Call(CodeSymbols.If, LNode.List(cond.Args.Last, block, LNode.Call(CodeSymbols.Break))))).SetStyle(NodeStyle.Statement))));
             }
             else
             {
                 return(stmt.WithArgChanged(1, block));
             }
         }
         else if ((attrs = stmt.Attrs).IsEmpty | true && stmt.Calls(CodeSymbols.DoWhile, 2) && (block = stmt.Args[0]) != null && (cond = stmt.Args[1]) != null)
         {
             block = EliminateSequenceExpressionsInChildStmt(block);
             cond  = BubbleUpBlocks(cond);
             if (cond.CallsMin(__numrunSequence, 1))
             {
                 var continue_N = F.Id(NextTempName(Context, "continue_"));
                 var bodyStmts  = block.AsList(S.Braces);
                 bodyStmts.AddRange(cond.Args.WithoutLast(1));
                 bodyStmts.Add(LNode.Call(CodeSymbols.Assign, LNode.List(continue_N, cond.Args.Last)).SetStyle(NodeStyle.Operator));
                 return(LNode.Call(LNode.List(attrs), CodeSymbols.For, LNode.List(LNode.Call(CodeSymbols.AltList, LNode.List(LNode.Call(CodeSymbols.Var, LNode.List(LNode.Id(CodeSymbols.Bool), LNode.Call(CodeSymbols.Assign, LNode.List(continue_N, LNode.Literal(true))))))), continue_N, LNode.Call(CodeSymbols.AltList), LNode.Call(CodeSymbols.Braces, LNode.List(bodyStmts)).SetStyle(NodeStyle.Statement))));
             }
             else
             {
                 return(stmt.WithArgChanged(0, block));
             }
         }
         else if ((attrs = stmt.Attrs).IsEmpty | true && stmt.Calls(CodeSymbols.For, 4) && stmt.Args[0].Calls(CodeSymbols.AltList) && (cond = stmt.Args[1]) != null && stmt.Args[2].Calls(CodeSymbols.AltList) && (block = stmt.Args[3]) != null)
         {
             inits = stmt.Args[0].Args;
             incs  = stmt.Args[2].Args;
             return(ESEInForLoop(stmt, attrs, inits, cond, incs, block));
         }
         else if ((attrs = stmt.Attrs).IsEmpty | true && stmt.Calls(CodeSymbols.ForEach, 3) && (tmp_11 = stmt.Args[0]) != null && tmp_11.Calls(CodeSymbols.Var, 2) && (type = tmp_11.Args[0]) != null && (loopVar = tmp_11.Args[1]) != null && (collection = stmt.Args[1]) != null && (block = stmt.Args[2]) != null)
         {
             block      = EliminateSequenceExpressionsInChildStmt(block);
             collection = BubbleUpBlocks(collection);
             if (collection.CallsMin(__numrunSequence, 1))
             {
                 return(LNode.Call(LNode.List(attrs), CodeSymbols.Braces, LNode.List().AddRange(collection.Args.WithoutLast(1)).Add(LNode.Call(CodeSymbols.ForEach, LNode.List(LNode.Call(CodeSymbols.Var, LNode.List(type, loopVar)), collection.Args.Last, block)))).SetStyle(NodeStyle.Statement));
             }
             else
             {
                 return(stmt.WithArgChanged(stmt.Args.Count - 1, block));
             }
         }
         else if ((attrs = stmt.Attrs).IsEmpty | true && stmt.Calls(CodeSymbols.Var, 2) && (type = stmt.Args[0]) != null && (tmp_12 = stmt.Args[1]) != null && tmp_12.Calls(CodeSymbols.Assign, 2) && (name = tmp_12.Args[0]) != null && (initValue = tmp_12.Args[1]) != null)
         {
             var initValue_apos = BubbleUpBlocks(initValue);
             if (initValue_apos != initValue)
             {
                 {
                     LNode         last;
                     VList <LNode> stmts;
                     if (initValue_apos.CallsMin((Symbol)"#runSequence", 1) && (last = initValue_apos.Args[initValue_apos.Args.Count - 1]) != null)
                     {
                         stmts = initValue_apos.Args.WithoutLast(1);
                         return(LNode.Call((Symbol)"#runSequence", LNode.List().AddRange(stmts).Add(LNode.Call(LNode.List(attrs), CodeSymbols.Var, LNode.List(type, LNode.Call(CodeSymbols.Assign, LNode.List(name, last)))))));
                     }
                     else
                     {
                         return(LNode.Call(LNode.List(attrs), CodeSymbols.Var, LNode.List(type, LNode.Call(CodeSymbols.Assign, LNode.List(name, initValue_apos)))));
                     }
                 }
             }
         }
         else if (stmt.CallsMin(S.Try, 2))
         {
             return(ESEInTryStmt(stmt));
         }
         else if (stmt.HasSpecialName && stmt.ArgCount >= 1 && stmt.Args.Last.Calls(S.Braces))
         {
             return(ProcessBlockCallStmt(stmt, stmt.ArgCount - 1));
         }
         else
         {
             // Ordinary expression statement
             return(BubbleUpBlocks(stmt, stmtContext: true));
         }
     }
     return(stmt);
 }
Пример #25
0
            private void MakeArgListTests(LNodeList patternArgs, ref LNode candidate)
            {
                // Note: at this point we can assume that the quantity of
                // arguments has already been checked and is not too small.
                Symbol varArgSym  = null;
                LNode  varArgCond = null;
                int    i;

                for (i = 0; i < patternArgs.Count; i++)
                {
                    MakeTestExpr(patternArgs[i], LNode.Call(CodeSymbols.IndexBracks, LNode.List(LNode.Call(CodeSymbols.Dot, LNode.List(candidate, LNode.Id((Symbol)"Args"))).SetStyle(NodeStyle.Operator), F.Literal(i))).SetStyle(NodeStyle.Operator), out varArgSym, out varArgCond);
                    if (varArgSym != null)
                    {
                        break;
                    }
                }
                int i2 = i + 1;

                for (int left = patternArgs.Count - i2; i2 < patternArgs.Count; i2++)
                {
                    Symbol varArgSym2  = null;
                    LNode  varArgCond2 = null;
                    MakeTestExpr(patternArgs[i2], LNode.Call(CodeSymbols.IndexBracks, LNode.List(LNode.Call(CodeSymbols.Dot, LNode.List(candidate, LNode.Id((Symbol)"Args"))).SetStyle(NodeStyle.Operator), LNode.Call(CodeSymbols.Sub, LNode.List(LNode.Call(CodeSymbols.Dot, LNode.List(LNode.Call(CodeSymbols.Dot, LNode.List(candidate, LNode.Id((Symbol)"Args"))).SetStyle(NodeStyle.Operator), LNode.Id((Symbol)"Count"))).SetStyle(NodeStyle.Operator), F.Literal(left))).SetStyle(NodeStyle.Operator))).SetStyle(NodeStyle.Operator), out varArgSym2, out varArgCond2);
                    if (varArgSym2 != null)
                    {
                        Context.Sink.Error(patternArgs[i2], "More than a single $(...varargs) variable is not supported in a single argument list.");
                        break;
                    }
                    left--;
                }
                if (varArgSym != null && (varArgSym != __ || varArgCond != null))
                {
                    // Extract variable arg list
                    LNode varArgSymId = F.Id(varArgSym);
                    LNode grabVarArgs;
                    if (i == 0 && patternArgs.Count == 1)
                    {
                        grabVarArgs = LNode.Call(CodeSymbols.Assign, LNode.List(varArgSymId, LNode.Call(CodeSymbols.Dot, LNode.List(candidate, LNode.Id((Symbol)"Args"))).SetStyle(NodeStyle.Operator))).SetStyle(NodeStyle.Operator);
                    }
                    else if (i == 0 && patternArgs.Count > 1)
                    {
                        var fixedArgsLit = F.Literal(patternArgs.Count - 1);
                        grabVarArgs = LNode.Call(CodeSymbols.Assign, LNode.List(varArgSymId, LNode.Call(LNode.Call(CodeSymbols.Dot, LNode.List(LNode.Call(CodeSymbols.Dot, LNode.List(candidate, LNode.Id((Symbol)"Args"))).SetStyle(NodeStyle.Operator), LNode.Id((Symbol)"WithoutLast"))).SetStyle(NodeStyle.Operator), LNode.List(fixedArgsLit)))).SetStyle(NodeStyle.Operator);
                    }
                    else
                    {
                        var varArgStartLit = F.Literal(i);
                        var fixedArgsLit   = F.Literal(patternArgs.Count - 1);
                        if (i + 1 == patternArgs.Count)
                        {
                            grabVarArgs = LNode.Call(CodeSymbols.Assign, LNode.List(varArgSymId, LNode.Call(CodeSymbols.New, LNode.List(LNode.Call((Symbol)"LNodeList", LNode.List(LNode.Call(LNode.Call(CodeSymbols.Dot, LNode.List(LNode.Call(CodeSymbols.Dot, LNode.List(candidate, LNode.Id((Symbol)"Args"))).SetStyle(NodeStyle.Operator), LNode.Id((Symbol)"Slice"))).SetStyle(NodeStyle.Operator), LNode.List(varArgStartLit)))))))).SetStyle(NodeStyle.Operator);
                        }
                        else
                        {
                            grabVarArgs = LNode.Call(CodeSymbols.Assign, LNode.List(varArgSymId, LNode.Call(CodeSymbols.New, LNode.List(LNode.Call((Symbol)"LNodeList", LNode.List(LNode.Call(LNode.Call(CodeSymbols.Dot, LNode.List(LNode.Call(CodeSymbols.Dot, LNode.List(candidate, LNode.Id((Symbol)"Args"))).SetStyle(NodeStyle.Operator), LNode.Id((Symbol)"Slice"))).SetStyle(NodeStyle.Operator), LNode.List(varArgStartLit, LNode.Call(CodeSymbols.Sub, LNode.List(LNode.Call(CodeSymbols.Dot, LNode.List(LNode.Call(CodeSymbols.Dot, LNode.List(candidate, LNode.Id((Symbol)"Args"))).SetStyle(NodeStyle.Operator), LNode.Id((Symbol)"Count"))).SetStyle(NodeStyle.Operator), fixedArgsLit)).SetStyle(NodeStyle.Operator))))))))).SetStyle(NodeStyle.Operator);
                        }
                    }

                    // Add an extra condition on the $(...list) if requested by user
                    if (varArgCond != null || IsMultiCase)
                    {
                        Tests.Add(LNode.Call(CodeSymbols.OrBits, LNode.List(LNode.Call(CodeSymbols.Dot, LNode.List(grabVarArgs.PlusAttrs(LNode.List(LNode.InParensTrivia)), LNode.Id((Symbol)"IsEmpty"))).SetStyle(NodeStyle.Operator), LNode.Literal(true))).SetStyle(NodeStyle.Operator));
                        Tests.Add(varArgCond);
                    }
                    else
                    {
                        ThenClause.Add(grabVarArgs);
                    }
                }
            }
Пример #26
0
        public static LNode concat(LNode node, IMacroContext context)
        {
            var result = ConcatCore(node, out var attrs, context.Sink);

            return(result == null ? null : LNode.Literal(result.ToString(), node).WithAttrs(attrs));
        }
Пример #27
0
            void GenCodeForPattern(LNode input, LNode pattern, string defaultPropName = null)
            {
                // Get the parts of the pattern, e.g. `$x is T(sp)` => varBinding=x, isType=T, sp is returned
                bool          refExistingVar;
                LNode         varBinding, cmpExpr, isType, inRange, propName;
                VList <LNode> subPatterns, conditions;

                GetPatternComponents(pattern, out propName, out varBinding, out refExistingVar, out cmpExpr, out isType, out inRange, out subPatterns, out conditions);

                if (defaultPropName == null)                    // Outermost pattern
                {
                    if (propName != null)
                    {
                        _context.Sink.Error(propName, "match: property name not allowed on outermost pattern");
                    }
                }
                else
                {
                    if ((propName = propName ?? LNode.Id(defaultPropName, pattern)) != null)
                    {
                        input = LNode.Call(CodeSymbols.Dot, LNode.List(input, propName)).SetStyle(NodeStyle.Operator);
                    }
                }

                // For a pattern like `is Type varBinding(subPatterns) in A...B && conds`,
                // our goal is to generate code like this:
                //
                //   var tmp_1 = $input; // temp var created unless $input looks simple
                //   if (tmp_1 is Type) {
                //     Type varBinding = (Type)tmp_1;
                //     if (varBinding >= A && varBinding <= B && /* code for matching subPatterns */)
                //         if (conds)
                //             $handler;
                //   }
                if (isType != null)
                {
                    if ((cmpExpr ?? inRange ?? varBinding) != null)
                    {
                        // input will be used multiple times, so consider making a tmp var.
                        if (!LooksLikeSimpleValue(input))
                        {
                            PutStmt(TempVarDecl(_context, input, out input));
                        }
                    }

                    PutCond(LNode.Call(CodeSymbols.Is, LNode.List(input, isType)).SetStyle(NodeStyle.Operator));

                    if (varBinding == null && ((cmpExpr ?? inRange) != null || subPatterns.Count > 0))
                    {
                        // we'll need another temp variable to hold the same value, casted.
                        varBinding = LNode.Id(NextTempName(_context), isType);
                    }
                }

                if (varBinding != null)
                {
                    if (isType != null)
                    {
                        if (refExistingVar)
                        {
                            PutStmt(LNode.Call(CodeSymbols.Assign, LNode.List(varBinding, LNode.Call(CodeSymbols.Cast, LNode.List(input, isType)).SetStyle(NodeStyle.Operator))).SetStyle(NodeStyle.Operator));
                        }
                        else
                        {
                            PutStmt(LNode.Call(CodeSymbols.Var, LNode.List(isType, LNode.Call(CodeSymbols.Assign, LNode.List(varBinding, LNode.Call(CodeSymbols.Cast, LNode.List(input, isType)).SetStyle(NodeStyle.Operator))))));
                        }
                    }
                    else
                    {
                        if (refExistingVar)
                        {
                            PutStmt(LNode.Call(CodeSymbols.Assign, LNode.List(varBinding, input)).SetStyle(NodeStyle.Operator));
                        }
                        else
                        {
                            PutStmt(LNode.Call(CodeSymbols.Var, LNode.List(LNode.Missing, LNode.Call(CodeSymbols.Assign, LNode.List(varBinding, input)))));
                        }
                    }
                    input = varBinding;
                }

                if (cmpExpr != null)                    // do equality test
                {
                    if (cmpExpr.Value == null)
                    {
                        PutCond(LNode.Call(CodeSymbols.Eq, LNode.List(input, LNode.Literal(null))).SetStyle(NodeStyle.Operator));
                    }
                    else
                    {
                        PutCond(LNode.Call(LNode.Call(CodeSymbols.Dot, LNode.List(cmpExpr, LNode.Id((Symbol)"Equals"))).SetStyle(NodeStyle.Operator), LNode.List(input)));
                    }
                }

                // Generate code for subpatterns
                for (int itemIndex = 0; itemIndex < subPatterns.Count; itemIndex++)
                {
                    var subPattern = subPatterns[itemIndex];
                    GenCodeForPattern(input, subPattern, "Item" + (itemIndex + 1));
                }

                if (inRange != null)
                {
                    PutCond(LNode.Call(CodeSymbols.In, LNode.List(input, inRange)).SetStyle(NodeStyle.Operator));
                }

                foreach (var cond in conditions)
                {
                    PutCond(cond);
                }
            }
Пример #28
0
 public static LNode match(LNode node, IMacroContext context)
 {
     {
         LNode         input;
         VList <LNode> contents;
         if (node.Args.Count == 2 && (input = node.Args[0]) != null && node.Args[1].Calls(CodeSymbols.Braces))
         {
             contents = node.Args[1].Args;
             var outputs = new WList <LNode>();
             input = MaybeAddTempVarDecl(context, input, outputs);
             int next_i = 0;
             for (int case_i = 0; case_i < contents.Count; case_i = next_i)
             {
                 var @case = contents[case_i];
                 if (!IsCaseLabel(@case))
                 {
                     return(Reject(context, contents[0], "In 'match': expected 'case' statement"));
                 }
                 for (next_i = case_i + 1; next_i < contents.Count; next_i++)
                 {
                     var stmt = contents[next_i];
                     if (IsCaseLabel(stmt))
                     {
                         break;
                     }
                     if (stmt.Calls(S.Break, 0))
                     {
                         next_i++;
                         break;
                     }
                 }
                 var handler = new VList <LNode>(contents.Slice(case_i + 1, next_i - (case_i + 1)));
                 if (@case.Calls(S.Case) && @case.Args.Count > 0)
                 {
                     var codeGen = new CodeGeneratorForMatchCase(context, input, handler);
                     foreach (var pattern in @case.Args)
                     {
                         outputs.Add(codeGen.GenCodeForPattern(pattern));
                     }
                 }
                 else
                 {
                     outputs.Add(LNode.Call(CodeSymbols.Braces, LNode.List(handler)).SetStyle(NodeStyle.Statement));
                     if (next_i < contents.Count)
                     {
                         context.Write(Severity.Error, contents[next_i], "The default branch must be the final branch in a 'match' statement.");
                     }
                 }
             }
             return(LNode.Call(CodeSymbols.DoWhile, LNode.List(outputs.ToVList().AsLNode(S.Braces), LNode.Literal(false))));
         }
     }
     return(null);
 }
Пример #29
0
 public Either <Symbol, ILogMessage> TryPrint(object value, Symbol typeMarker, out StringBuilder sb, NodeStyle style = NodeStyle.Default) =>
 TryPrint(LNode.Literal(SourceRange.Synthetic, new LiteralValue(value, typeMarker), style), out sb);
Пример #30
0
 static LiteralNode CL(object value, string symbol) =>
 LNode.Literal(SourceRange.Synthetic, new LiteralValue(value, (Symbol)symbol));