Beispiel #1
0
        public void TestAddRange()
        {
            var list = _newList();

            list.AddRange(Range.Inclusive(1, 3));
            list.AddRange(Enumerable.Range(5, 3));
            ExpectList(list, 1, 2, 3, 5, 6, 7);
            list.AddRange(Range.Inclusive(10, 11));
            list.AddRange(Enumerable.Range(20, 2));
            ExpectList(list, 1, 2, 3, 5, 6, 7, 10, 11, 20, 21);
            list.AddRange(Range.Inclusive(30, 30));
            list.AddRange(Enumerable.Range(40, 1));
            ExpectList(list, 1, 2, 3, 5, 6, 7, 10, 11, 20, 21, 30, 40);
            list.AddRange(Range.ExcludeHi(0, 0));
            list.AddRange(Enumerable.Repeat(0, 0));
            ExpectList(list, 1, 2, 3, 5, 6, 7, 10, 11, 20, 21, 30, 40);

            list.AddRange(Range.Only(-99));
            if (list.First() == -99)
            {
                // It's a sorted list.
                list.AddRange(ListExt.Single(4));
                ExpectList(list, -99, 1, 2, 3, 4, 5, 6, 7, 10, 11, 20, 21, 30, 40);
                list.AddRange(Enumerable.Range(-2, 3));
                ExpectList(list, -99, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 10, 11, 20, 21, 30, 40);
                list.AddRange(Enumerable.Range(12, 8));
                ExpectList(list, -99, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 30, 40);
            }
            else
            {
                ExpectList(list, 1, 2, 3, 5, 6, 7, 10, 11, 20, 21, 30, 40, -99);
            }
        }
Beispiel #2
0
 private void AddShapeCore(Shape newShape, bool @do)
 {
     newShape.OnBeingAdded(this);
     _core.Shapes.Add(newShape);
     if (AfterShapesAdded != null && @do)
     {
         AfterShapesAdded(ListExt.Single(newShape));
     }
 }
Beispiel #3
0
        public static LNode use_symbols(LNode input, IMacroContext context)
        {
            var args_body = context.GetArgsAndBody(true);

            // Decode options (TODO: invent a simpler approach)
            string prefix    = "sy_";
            var    inherited = new HashSet <Symbol>();

            foreach (var pair in MacroContext.GetOptions(args_body.A))
            {
                if (pair.Key.Name == "prefix" && pair.Value.IsId)
                {
                    prefix = pair.Value.Name.Name;
                }
                else if (pair.Key.Name == "inherit" && pair.Value.Value is Symbol)
                {
                    inherited.Add((Symbol)pair.Value.Value);
                }
                else if (pair.Key.Name == "inherit" && (pair.Value.Calls(S.Braces) || pair.Value.Calls(S.Tuple)) && pair.Value.Args.All(n => n.Value is Symbol))
                {
                    foreach (var arg in pair.Value.Args)
                    {
                        inherited.Add((Symbol)arg.Value);
                    }
                }
                else
                {
                    context.Sink.Write(Severity.Warning, pair.Value, "Unrecognized parameter. Expected prefix:id or inherit:{@@A; @@B; ...})");
                }
            }

            // Replace all symbols while collecting a list of them
            var           symbols = new Dictionary <Symbol, LNode>();
            VList <LNode> output  = args_body.B.SmartSelect(stmt => stmt.ReplaceRecursive(n => {
                var sym = n.Value as Symbol;
                if (n.IsLiteral && sym != null)
                {
                    return(symbols[sym] = LNode.Id(prefix + EcsNodePrinter.SanitizeIdentifier(sym.Name)));
                }
                return(null);
            }));

            // Return updated code with variable declaration at the top for all non-inherit symbols used.
            var _Symbol = F.Id("Symbol");
            var vars    = (from sym in symbols
                           where !inherited.Contains(sym.Key)
                           select F.Call(S.Assign, sym.Value,
                                         F.Call(S.Cast, F.Literal(sym.Key.Name), _Symbol))).ToList();

            if (vars.Count > 0)
            {
                output.Insert(0, F.Call(S.Var, ListExt.Single(_Symbol).Concat(vars))
                              .WithAttrs(input.Attrs.Add(F.Id(S.Static)).Add(F.Id(S.Readonly))));
            }
            return(F.Call(S.Splice, output));
        }
Beispiel #4
0
 public override bool TrySet(int index, T value)
 {
     if ((uint)index < (uint)_list.Count)
     {
         if (_owner != null)
         {
             var chgList = ListExt.Single(value);
             _owner.OnListChanging(this, new ListChangeInfo <T>(NotifyCollectionChangedAction.Replace, index, 0, chgList));
         }
         return(_list.TrySet(index, value));
     }
     return(false);
 }
Beispiel #5
0
 public override void Insert(int index, T item)
 {
     if ((uint)index > (uint)_list.Count)
     {
         throw new ArgumentOutOfRangeException("index");
     }
     if (_owner != null)
     {
         var chgList = ListExt.Single(item);
         _owner.OnListChanging(this, new ListChangeInfo <T>(NotifyCollectionChangedAction.Add, index, 1, chgList));
     }
     _list.Insert(index, item);
 }
Beispiel #6
0
 public void AddShape(Shape newShape)
 {
     _undoStack.Do(@do => {
         if (@do)
         {
             AddShapeCore(newShape, true);
         }
         else
         {
             RemoveShapesCore(ListExt.Single(newShape), @do);
         }
     }, true);
 }
Beispiel #7
0
        public override IEnumerable <ITask> Prerequisites(IEnumerable <ITask> concurrentTasks)
        {
            var clash = concurrentTasks.FirstOrDefault(task => {
                // no clash if different AppDomain (we can't access private members across domains anyway)
                if (RemotingServices.IsTransparentProxy(task))
                {
                    return(false);
                }
                var utt = task as UnitTestTask;
                return(utt != null && utt._instance == _instance);
            });

            if (clash == null)
            {
                return(null);
            }
            return(ListExt.Single(clash));
        }
Beispiel #8
0
 static IEnumerable <LNode> GetNamespaces(LNode multiName)
 {
     {
         LNode         outerNamespace;
         VList <LNode> args;
         if (multiName.Calls(CodeSymbols.Dot) || multiName.Calls(CodeSymbols.Of))
         {
         }
         else if (multiName.IsCall && (outerNamespace = multiName.Target) != null)
         {
             args = multiName.Args;
             if (args.Count == 1 && args[0].Calls(S.Braces))
             {
                 args = args[0].Args;
             }
             return(args.SelectMany(arg => GetNamespaces(arg) ?? ListExt.Single(arg)).Select(subNS => MergeIdentifiers(outerNamespace, subNS)));
         }
     }
     return(null);
 }
        protected override IEnumerator <Token> MakeDedentToken(Token tokenBeforeDedent, ref Maybe <Token> tokenAfterDedent)
        {
            var next = tokenAfterDedent.Or(default(Token));

            if (next.Type() == TokenType.Colon)
            {
                // Note: we shouldn't delete the colon by setting tokenAfterDedent=NoValue. Consider:
                //   line1:
                //     line2:
                //       line3()
                //   :line4
                // Here, two dedents are generated. If the first dedent deletes
                // the colon, the second one will not see the colon and will not
                // be aware that it should suppress a semicolon.
                return(ListExt.Single(new Token((int)TokenType.Dedent, next.StartIndex, 0, 0, null)).GetEnumerator());
            }
            else
            {
                return(((IEnumerable <Token>) new Token[] {
                    new Token((int)TokenType.Dedent, next.StartIndex, 0, 0, null),
                    new Token((int)TokenType.Semicolon, next.StartIndex, 0, 0, CodeSymbols.Semicolon),
                }).GetEnumerator());
            }
        }
Beispiel #10
0
        public static LNode matchCode(LNode node, IMacroContext context)
        {
            if (node.AttrNamed(S.Static) != null)
            {
                return(null);                   // this case is handled by static_matchCode macro
            }
            var       args_body = context.GetArgsAndBody(false);
            LNodeList args = args_body.Item1, body = args_body.Item2;

            if (args.Count != 1 || body.Count < 1)
            {
                return(null);
            }
            var cases = GetCases(body, context.Sink);

            if (cases.IsEmpty)
            {
                return(null);
            }

            var output = new WList <LNode>();
            var var    = MaybeAddTempVarDecl(context, args[0], output);

            var ifClauses = new List <Pair <LNode, LNode> >();
            var cmc       = new CodeMatchContext {
                Context = context
            };

            foreach (var @case in cases)
            {
                cmc.ThenClause.Clear();
                // e.g. case [$(..._)] Foo($x + 1, $y) =>
                //      LNode x, y, tmp9;
                //      if (var.Calls((Symbol) "Foo", 2) && (tmp9 = var.Args[0]).Calls(CodeSymbols.Plus, 2)
                //          && (x = tmp9.Args[0]) != null // this will never be null, but we want to put it the assignment in the 'if' statement
                //          && 1.Equals(tmp9.Args[1].Value) && (y = var.Args[1]) != null) { ... }
                LNode testExpr = null;
                if (@case.Key.Count > 0)
                {
                    if (cmc.IsMultiCase = @case.Key.Count > 1)
                    {
                        cmc.UsageCounters.Clear();
                        testExpr = @case.Key.Aggregate((LNode)null, (test, pattern) => {
                            test = LNode.MergeBinary(test, cmc.MakeTopTestExpr(pattern, var), S.Or);
                            return(test);
                        });
                        foreach (var pair in cmc.UsageCounters.Where(p => p.Value < @case.Key.Count))
                        {
                            if (cmc.NodeVars.ContainsKey(pair.Key))
                            {
                                cmc.NodeVars[pair.Key] = true;
                            }
                            if (cmc.ListVars.ContainsKey(pair.Key))
                            {
                                cmc.ListVars[pair.Key] = true;
                            }
                        }
                    }
                    else
                    {
                        testExpr = cmc.MakeTopTestExpr(@case.Key[0], var);
                    }
                }
                var handler = F.Braces(@case.Value);
                if (cmc.ThenClause.Count > 0)
                {
                    handler = LNode.MergeLists(F.Braces(cmc.ThenClause), handler, S.Braces);
                }
                ifClauses.Add(Pair.Create(testExpr, handler));
            }

            LNode ifStmt = null;

            for (int i = ifClauses.Count - 1; i >= 0; i--)
            {
                if (ifClauses[i].Item1 == null)
                {
                    if (ifStmt == null)
                    {
                        ifStmt = ifClauses[i].Item2;
                    }
                    else
                    {
                        context.Sink.Error(node, "The default case must appear last, and there can be only one.");
                    }
                }
                else
                {
                    if (ifStmt == null)
                    {
                        ifStmt = F.Call(S.If, ifClauses[i].Item1, ifClauses[i].Item2);
                    }
                    else
                    {
                        ifStmt = F.Call(S.If, ifClauses[i].Item1, ifClauses[i].Item2, ifStmt);
                    }
                }
            }

            if (cmc.NodeVars.Count > 0)
            {
                output.Add(F.Call(S.Var, ListExt.Single(F.Id("LNode")).Concat(
                                      cmc.NodeVars.OrderBy(v => v.Key.Name).Select(kvp => kvp.Value ? F.Call(S.Assign, F.Id(kvp.Key), F.Null) : F.Id(kvp.Key)))));
            }
            if (cmc.ListVars.Count > 0)
            {
                LNode type = LNode.Id((Symbol)"LNodeList");
                output.Add(F.Call(S.Var, ListExt.Single(type).Concat(
                                      cmc.ListVars.OrderBy(v => v.Key.Name).Select(kvp => kvp.Value ? LNode.Call(CodeSymbols.Assign, LNode.List(F.Id(kvp.Key), LNode.Call(CodeSymbols.Default, LNode.List(type)))).SetStyle(NodeStyle.Operator) : F.Id(kvp.Key)))));
            }
            if (output.Count == 0)
            {
                return(ifStmt.IncludingTriviaFrom(node));
            }
            else
            {
                output.Add(ifStmt);
                return(F.Braces(output.ToVList()).IncludingTriviaFrom(node));
            }
        }
Beispiel #11
0
        [LexicalMacro("matchCode (var) { case ...: ... }; // In LES, use a => b instead of case a: b", "Attempts to match and deconstruct a Loyc tree against a series of cases with patterns, e.g. " + "`case $a + $b:` expects a tree that calls `+` with two parameters, placed in new variables called a and b. " + "`break` is not required or recognized at the end of each case's handler (code block). " + "Use `$(...x)` to gather zero or more parameters into a list `x`. " + "Use `case pattern1, pattern2:` in EC# to handle multiple cases with the same handler.")] public static LNode matchCode(LNode node, IMacroContext context)
        {
            var           args_body = context.GetArgsAndBody(true);
            VList <LNode> args = args_body.Item1, body = args_body.Item2;

            if (args.Count != 1 || body.Count < 1)
            {
                return(null);
            }
            var cases  = GetCases(body, context.Sink);

            if (cases.IsEmpty)
            {
                return(null);
            }
            var output = new WList <LNode>();
            var @var   = MaybeAddTempVarDecl(args[0], output);
            var ifClauses = new List <Pair <LNode, LNode> >();
            var cmc    = new CodeMatchContext {
                Context = context
            };

            foreach (var @case in cases)
            {
                cmc.ThenClause.Clear();
                LNode testExpr = null;
                if (@case.Key.Count > 0)
                {
                    if (cmc.IsMultiCase = @case.Key.Count > 1)
                    {
                        cmc.UsageCounters.Clear();
                        testExpr = @case.Key.Aggregate((LNode)null, (test, pattern) => {
                            test = LNode.MergeBinary(test, cmc.MakeTopTestExpr(pattern, @var), S.Or);
                            return(test);
                        });
                        foreach (var pair in cmc.UsageCounters.Where(p => p.Value < @case.Key.Count))
                        {
                            if (cmc.NodeVars.ContainsKey(pair.Key))
                            {
                                cmc.NodeVars[pair.Key] = true;
                            }
                            if (cmc.ListVars.ContainsKey(pair.Key))
                            {
                                cmc.ListVars[pair.Key] = true;
                            }
                        }
                    }
                    else
                    {
                        testExpr = cmc.MakeTopTestExpr(@case.Key[0], @var);
                    }
                }
                var handler = @case.Value;
                if (cmc.ThenClause.Count > 0)
                {
                    handler = LNode.MergeLists(F.Braces(cmc.ThenClause), handler, S.Braces);
                }
                ifClauses.Add(Pair.Create(testExpr, handler));
            }
            LNode ifStmt = null;

            for (int i = ifClauses.Count - 1; i >= 0; i--)
            {
                if (ifClauses[i].Item1 == null)
                {
                    if (ifStmt == null)
                    {
                        ifStmt = ifClauses[i].Item2;
                    }
                    else
                    {
                        context.Sink.Write(Severity.Error, node, "The default case must appear last, and there can be only one.");
                    }
                }
                else
                {
                    if (ifStmt == null)
                    {
                        ifStmt = F.Call(S.If, ifClauses[i].Item1, ifClauses[i].Item2);
                    }
                    else
                    {
                        ifStmt = F.Call(S.If, ifClauses[i].Item1, ifClauses[i].Item2, ifStmt);
                    }
                }
            }
            if (cmc.NodeVars.Count > 0)
            {
                output.Add(F.Call(S.Var, ListExt.Single(F.Id("LNode")).Concat(cmc.NodeVars.OrderBy(v => v.Key.Name).Select(kvp => kvp.Value ? F.Call(S.Assign, F.Id(kvp.Key), F.Null) : F.Id(kvp.Key)))));
            }
            if (cmc.ListVars.Count > 0)
            {
                LNode type = LNode.Call(CodeSymbols.Of, LNode.List(LNode.Id((Symbol)"VList"), LNode.Id((Symbol)"LNode")));
                output.Add(F.Call(S.Var, ListExt.Single(type).Concat(cmc.ListVars.OrderBy(v => v.Key.Name).Select(kvp => kvp.Value ? LNode.Call(CodeSymbols.Assign, LNode.List(F.Id(kvp.Key), LNode.Call(CodeSymbols.Default, LNode.List(type)))).SetStyle(NodeStyle.Operator) : F.Id(kvp.Key)))));
            }
            if (output.Count == 0)
            {
                return(ifStmt);
            }
            else
            {
                output.Add(ifStmt);
                return(F.Braces(output.ToVList()));
            }
        }
Beispiel #12
0
        public static LNodeList UseSymbolsCore(LNodeList symbolAttrs, LNodeList options, LNodeList body, IMacroContext context, bool inType)
        {
            // Decode options (TODO: invent a simpler approach)
            string prefix    = "sy_";
            var    inherited = new HashSet <Symbol>();

            foreach (var pair in MacroContext.GetOptions(options))
            {
                if (pair.Key.Name.Name == "prefix" && pair.Value.IsId)
                {
                    prefix = pair.Value.Name.Name;
                }
                else if (pair.Key.Name.Name == "inherit" && pair.Value.Value is Symbol)
                {
                    inherited.Add((Symbol)pair.Value.Value);
                }
                else if (pair.Key.Name.Name == "inherit" && (pair.Value.Calls(S.Braces) || pair.Value.Calls(S.Tuple)) && pair.Value.Args.All(n => n.Value is Symbol))
                {
                    foreach (var arg in pair.Value.Args)
                    {
                        inherited.Add((Symbol)arg.Value);
                    }
                }
                else
                {
                    context.Sink.Warning(pair.Key, "Unrecognized parameter. Expected prefix:id or inherit:{@@A; @@B; ...})");
                }
            }

            // Replace all symbols while collecting a list of them
            var       symbols = new Dictionary <Symbol, LNode>();
            LNodeList output  = body.SmartSelect(stmt =>
                                                 stmt.ReplaceRecursive(n => {
                if (!inType && n.ArgCount == 3)
                {
                    // Since we're outside any type, we must avoid creating symbol
                    // fields. When we cross into a type then we can start making
                    // Symbols by calling ourself recursively with inType=true
                    var kind = EcsValidators.SpaceDefinitionKind(n);
                    if (kind == S.Class || kind == S.Struct || kind == S.Interface || kind == S.Alias || kind == S.Trait)
                    {
                        var body2 = n.Args[2];
                        return(n.WithArgChanged(2, body2.WithArgs(UseSymbolsCore(symbolAttrs, options, body2.Args, context, true))));
                    }
                }
                var sym = n.Value as Symbol;
                if (n.IsLiteral && sym != null)
                {
                    return(symbols[sym] = LNode.Id(prefix + sym.Name));
                }
                return(null);
            })
                                                 );

            // Return updated code with variable declaration at the top for all non-inherit symbols used.
            var _Symbol = F.Id("Symbol");
            var vars    = (from sym in symbols
                           where !inherited.Contains(sym.Key)
                           select F.Call(S.Assign, sym.Value,
                                         F.Call(S.Cast, F.Literal(sym.Key.Name), _Symbol))).ToList();

            if (vars.Count > 0)
            {
                output.Insert(0, F.Call(S.Var, ListExt.Single(_Symbol).Concat(vars))
                              .WithAttrs(symbolAttrs.Add(F.Id(S.Static)).Add(F.Id(S.Readonly))));
            }
            return(output);
        }
Beispiel #13
0
        internal override int DoSingleOperation(ref AListSingleOperation <K, T> op, out AListNode <K, T> splitLeft, out AListNode <K, T> splitRight)
        {
            T   searchItem = op.Item;
            int index      = _list.BinarySearch(op.Key, op.CompareToKey, op.LowerBound);

            if (op.Found = (index >= 0))
            {
                op.Item = _list[index];                 // save old value
                if (op.RequireExactMatch && (searchItem == null ? op.Item == null : !searchItem.Equals(op.Item)))
                {
                    op.Found = false;
                }
            }
            else
            {
                index = ~index;
            }

            splitLeft     = splitRight = null;
            op.BaseIndex += (uint)index;

            if (op.Mode == AListOperation.Retrieve)
            {
                return(0);
            }

            if (op.Mode >= AListOperation.Add)
            {
                // Possible operations: Add, AddOrReplace, AddIfNotPresent, AddOrThrow
                if (_list.Count >= _maxNodeSize && (op.Mode == AListOperation.Add || !op.Found))
                {
                    op.BaseIndex -= (uint)index;
                    op.Item       = searchItem;
                    return(SplitAndAdd(ref op, out splitLeft, out splitRight));
                }

                if (op.Found && op.Mode != AListOperation.Add)
                {
                    if (op.Mode == AListOperation.AddOrThrow)
                    {
                        throw new KeyAlreadyExistsException();
                    }
                    else if (op.Mode == AListOperation.AddIfNotPresent)
                    {
                        return(0);
                    }
                }
                else                 // add new item
                {
                    if (HasListChanging(op.List))
                    {
                        CallListChanging(op.List, new ListChangeInfo <T>(NotifyCollectionChangedAction.Add, (int)op.BaseIndex, 1, ListExt.Single(searchItem)));
                    }

                    if (index == _list.Count)
                    {                           // Highest key may change
                        splitLeft            = this;
                        op.AggregateChanged |= 1;
                        op.AggregateKey      = op.List.GetKey(searchItem);
                    }

                    _list.AutoRaiseCapacity(1, _maxNodeSize);
                    _list.Insert(index, searchItem);

                    if (GetObserver(op.List) != null)
                    {
                        if ((op.AggregateChanged & 2) == 0)
                        {
                            GetObserver(op.List).ItemAdded(searchItem, this);
                        }
                    }
                    return(1);
                }
                Debug.Assert(op.Mode == AListOperation.AddOrReplace);
            }
            else if (op.Found)
            {
                // Possible operations: ReplaceIfPresent, Remove
                if (op.Mode == AListOperation.Remove)
                {
                    if (HasListChanging(op.List))
                    {
                        CallListChanging(op.List, new ListChangeInfo <T>(NotifyCollectionChangedAction.Remove, (int)op.BaseIndex, -1, null));
                    }

                    _list.RemoveAt(index);

                    if (index == _list.Count)
                    {                           // Highest key may change
                        splitLeft = this;
                        if (_list.Count != 0)
                        {
                            op.AggregateChanged |= 1;
                            op.AggregateKey      = op.List.GetKey(_list.Last);
                        }
                    }
                    else if (IsUndersized)
                    {
                        splitLeft = this;
                    }

                    if (GetObserver(op.List) != null)
                    {
                        Debug.Assert((op.AggregateChanged & 2) == 0);
                        GetObserver(op.List).ItemRemoved(op.Item, this);
                    }

                    return(-1);
                }
                Debug.Assert(op.Mode == AListOperation.ReplaceIfPresent);
            }
            else
            {
                Debug.Assert(op.Mode == AListOperation.Remove || op.Mode == AListOperation.ReplaceIfPresent);
                return(0);                // can't remove/replace because item was not found.
            }

            // Fallthrough action: replace existing item
            Debug.Assert(op.Found);
            if (HasListChanging(op.List))
            {
                CallListChanging(op.List, new ListChangeInfo <T>(NotifyCollectionChangedAction.Replace, (int)op.BaseIndex, 0, ListExt.Single(searchItem)));
            }

            _list[index] = searchItem;

            if (index + 1 == _list.Count)
            {                   // Highest key may change
                splitLeft            = this;
                op.AggregateChanged |= 1;
                op.AggregateKey      = op.List.GetKey(searchItem);
            }

            if (GetObserver(op.List) != null)
            {
                GetObserver(op.List).ItemRemoved(op.Item, this);
                GetObserver(op.List).ItemAdded(searchItem, this);
            }
            return(0);
        }
Beispiel #14
0
        public static LNode matchCode(LNode node, IMacroContext context)
        {
            var           args_body = context.GetArgsAndBody(true);
            VList <LNode> args = args_body.Item1, body = args_body.Item2;

            if (args.Count != 1 || body.Count < 1)
            {
                return(null);
            }
            var cases  = GetCases(body, context.Sink);

            if (cases.IsEmpty)
            {
                return(null);
            }
            var output = new WList <LNode>();
            var @var   = MaybeAddTempVarDecl(context, args[0], output);
            var ifClauses = new List <Pair <LNode, LNode> >();
            var cmc    = new CodeMatchContext {
                Context = context
            };

            foreach (var @case in cases)
            {
                cmc.ThenClause.Clear();
                LNode testExpr = null;
                if (@case.Key.Count > 0)
                {
                    if (cmc.IsMultiCase = @case.Key.Count > 1)
                    {
                        cmc.UsageCounters.Clear();
                        testExpr = @case.Key.Aggregate((LNode)null, (test, pattern) => {
                            test = LNode.MergeBinary(test, cmc.MakeTopTestExpr(pattern, @var), S.Or);
                            return(test);
                        });
                        foreach (var pair in cmc.UsageCounters.Where(p => p.Value < @case.Key.Count))
                        {
                            if (cmc.NodeVars.ContainsKey(pair.Key))
                            {
                                cmc.NodeVars[pair.Key] = true;
                            }
                            if (cmc.ListVars.ContainsKey(pair.Key))
                            {
                                cmc.ListVars[pair.Key] = true;
                            }
                        }
                    }
                    else
                    {
                        testExpr = cmc.MakeTopTestExpr(@case.Key[0], @var);
                    }
                }
                var handler = @case.Value;
                if (cmc.ThenClause.Count > 0)
                {
                    handler = LNode.MergeLists(F.Braces(cmc.ThenClause), handler, S.Braces);
                }
                ifClauses.Add(Pair.Create(testExpr, handler));
            }
            LNode ifStmt = null;

            for (int i = ifClauses.Count - 1; i >= 0; i--)
            {
                if (ifClauses[i].Item1 == null)
                {
                    if (ifStmt == null)
                    {
                        ifStmt = ifClauses[i].Item2;
                    }
                    else
                    {
                        context.Sink.Write(Severity.Error, node, "The default case must appear last, and there can be only one.");
                    }
                }
                else
                {
                    if (ifStmt == null)
                    {
                        ifStmt = F.Call(S.If, ifClauses[i].Item1, ifClauses[i].Item2);
                    }
                    else
                    {
                        ifStmt = F.Call(S.If, ifClauses[i].Item1, ifClauses[i].Item2, ifStmt);
                    }
                }
            }
            if (cmc.NodeVars.Count > 0)
            {
                output.Add(F.Call(S.Var, ListExt.Single(F.Id("LNode")).Concat(cmc.NodeVars.OrderBy(v => v.Key.Name).Select(kvp => kvp.Value ? F.Call(S.Assign, F.Id(kvp.Key), F.Null) : F.Id(kvp.Key)))));
            }
            if (cmc.ListVars.Count > 0)
            {
                LNode type = LNode.Call(CodeSymbols.Of, LNode.List(LNode.Id((Symbol)"VList"), LNode.Id((Symbol)"LNode")));
                output.Add(F.Call(S.Var, ListExt.Single(type).Concat(cmc.ListVars.OrderBy(v => v.Key.Name).Select(kvp => kvp.Value ? LNode.Call(CodeSymbols.Assign, LNode.List(F.Id(kvp.Key), LNode.Call(CodeSymbols.Default, LNode.List(type)))).SetStyle(NodeStyle.Operator) : F.Id(kvp.Key)))));
            }
            if (output.Count == 0)
            {
                return(ifStmt);
            }
            else
            {
                output.Add(ifStmt);
                return(F.Braces(output.ToVList()));
            }
        }