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); } }
private void AddShapeCore(Shape newShape, bool @do) { newShape.OnBeingAdded(this); _core.Shapes.Add(newShape); if (AfterShapesAdded != null && @do) { AfterShapesAdded(ListExt.Single(newShape)); } }
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)); }
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); }
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); }
public void AddShape(Shape newShape) { _undoStack.Do(@do => { if (@do) { AddShapeCore(newShape, true); } else { RemoveShapesCore(ListExt.Single(newShape), @do); } }, true); }
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)); }
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()); } }
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)); } }
[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())); } }
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); }
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); }
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())); } }