public static LNode unroll(LNode var, LNode cases, LNode body, IMessageSink sink) { if (!cases.Calls(S.Tuple) && !cases.Calls(S.Braces)) return Reject(sink, cases, "unroll: the right-hand side of 'in' should be a tuple"); // Maps identifiers => replacements. The integer counts how many times replacement occurred. var replacements = InternalList<Triplet<Symbol, LNode, int>>.Empty; if (var.IsId && !var.HasPAttrs()) { replacements.Add(Pair.Create(var.Name, (LNode)LNode.Missing, 0)); } else { var vars = var.Args; if ((var.Calls(S.Tuple) || var.Calls(S.Braces)) && vars.All(a => a.IsId && !a.HasPAttrs())) { replacements = new Triplet<Symbol, LNode, int>[vars.Count].AsInternalList(); for (int i = 0; i < vars.Count; i++) { replacements.InternalArray[i].A = vars[i].Name; // Check for duplicate names for (int j = 0; j < i; j++) if (replacements[i].A == replacements[j].A && replacements[i].A.Name != "_") sink.Write(Severity.Error, vars[i], "unroll: duplicate name in the left-hand tuple"); // non-fatal } } else return Reject(sink, cases, "unroll: the left-hand side of 'in' should be a simple identifier or a tuple of simple identifiers."); } UnrollCtx ctx = new UnrollCtx { Replacements = replacements }; WList<LNode> output = new WList<LNode>(); int iteration = 0; foreach (LNode replacement in cases.Args) { iteration++; bool tuple = replacement.Calls(S.Tuple) || replacement.Calls(S.Braces); int count = tuple ? replacement.ArgCount : 1; if (replacements.Count != count) { sink.Write(Severity.Error, replacement, "unroll, iteration {0}: Expected {1} replacement items, got {2}", iteration, replacements.Count, count); if (count < replacements.Count) continue; // too few } for (int i = 0; i < replacements.Count; i++) replacements.InternalArray[i].B = tuple ? replacement.Args[i] : replacement; if (body.Calls(S.Braces)) { foreach (LNode stmt in body.Args) output.Add(ctx.Replace(stmt).Value); } else output.Add(ctx.Replace(body).Value); } foreach (var r in replacements) if (r.C == 0 && !r.A.Name.StartsWith("_")) sink.Write(Severity.Warning, var, "Replacement variable '{0}' was never used", r.A); return body.With(S.Splice, output.ToVList()); }
public static LNode unroll(LNode var, VList <LNode> cases, LNode body, IMessageSink sink) { // Maps identifiers => replacements. The integer counts how many times replacement occurred. var replacements = InternalList <Triplet <Symbol, LNode, int> > .Empty; if (var.IsId && !var.HasPAttrs()) { replacements.Add(Pair.Create(var.Name, (LNode)LNode.Missing, 0)); } else { var vars = var.Args; if ((var.Calls(S.Tuple) || var.Calls(S.Braces)) && vars.All(a => a.IsId && !a.HasPAttrs())) { replacements = new Triplet <Symbol, LNode, int> [vars.Count].AsInternalList(); for (int i = 0; i < vars.Count; i++) { replacements.InternalArray[i].A = vars[i].Name; // Check for duplicate names for (int j = 0; j < i; j++) { if (replacements[i].A == replacements[j].A && replacements[i].A.Name != "_") { sink.Error(vars[i], "Duplicate name in the left-hand tuple"); // non-fatal } } } } else { return(Reject(sink, var, "The left-hand side of 'in' should be a simple identifier or a tuple of simple identifiers.")); } } UnrollCtx ctx = new UnrollCtx { Replacements = replacements }; WList <LNode> output = new WList <LNode>(); int iteration = 0; foreach (LNode replacement in cases) { iteration++; bool tuple = replacement.Calls(S.Tuple) || replacement.Calls(S.Braces); int count = tuple ? replacement.ArgCount : 1; if (replacements.Count != count) { sink.Error(replacement, "iteration {0}: Expected {1} replacement items, got {2}", iteration, replacements.Count, count); if (count < replacements.Count) { continue; // too few } } for (int i = 0; i < replacements.Count; i++) { replacements.InternalArray[i].B = tuple ? replacement.Args[i] : replacement; } if (body.Calls(S.Braces)) { foreach (LNode stmt in body.Args) { output.Add(ctx.Replace(stmt).Value); } } else { output.Add(ctx.Replace(body).Value); } } foreach (var r in replacements) { if (r.C == 0 && !r.A.Name.StartsWith("_")) { sink.Write(Severity.Warning, var, "Replacement variable '{0}' was never used", r.A); } } return(body.With(S.Splice, output.ToVList())); }