LNode GetOutputAsLNode() { WList <LNode> finalOutput = _handler.ToWList(); for (int end = _output.Count - 1; end >= 0; end--) { var tmp_10 = _output[end]; Mode mode = tmp_10.Item1; LNode code = tmp_10.Item2; if (mode == Mode.Condition) { // Merge adjacent conditions into the same if-statement int start = end; for (; start > 0 && _output[start - 1].A == mode; start--) { } LNode cond = _output[start].B; for (int i = start + 1; i <= end; i++) { cond = LNode.Call(CodeSymbols.And, LNode.List(cond, _output[i].B)).SetStyle(NodeStyle.Operator); } end = start; finalOutput = new WList <LNode> { LNode.Call(CodeSymbols.If, LNode.List(cond, finalOutput.ToLNodeList().AsLNode(S.Braces))) }; } else { finalOutput.Insert(0, code); } } return(finalOutput.ToLNodeList().AsLNode(S.Braces)); }
public void Generate(Rule rule) { CGH.BeginRule(rule); _currentRule = rule; _target = new WList <LNode>(); _laVarsNeeded = 0; _separatedMatchCounter = _stopLabelCounter = 0; _recognizerMode = rule.IsRecognizer; _labelsInUse.Clear(); Visit(rule.Pred); if (_laVarsNeeded != 0) { LNode laVars = F.Call(S.Var, CGH.LAType()); for (int i = 0; _laVarsNeeded != 0; i++, _laVarsNeeded >>= 1) { if ((_laVarsNeeded & 1) != 0) { laVars = laVars.PlusArg(F.Id("la" + i.ToString())); } } _target.Insert(0, laVars); } LNode method; if (rule.TryWrapperName != null) { Debug.Assert(rule.IsRecognizer); method = F.OnNewLine(CGH.CreateTryWrapperForRecognizer(rule)); _classBody.SpliceAdd(method, S.Splice); } method = CGH.CreateRuleMethod(rule, _target.ToLNodeList()); if (!rule.IsRecognizer) { method = F.OnNewLine(method); } _classBody.SpliceAdd(method, S.Splice); }
public static LNode unroll(LNode var, LNodeList 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(Triplet.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.ToLNodeList())); }
public static LNode match(LNode node, IMacroContext context) { { LNode input; LNodeList 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 LNodeList(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.StatementBlock)); 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.ToLNodeList().AsLNode(S.Braces), LNode.Literal(false)))); } } return(null); }