public void StmtList(ref RWList <LNode> exprs) { TT la0; exprs = exprs ?? new RWList <LNode>(); var next = SuperExprOptUntil(TT.Semicolon); // Line 187: (TT.Semicolon SuperExprOptUntil)* for (;;) { la0 = LA0; if (la0 == TT.Semicolon) { exprs.Add(next); Skip(); next = SuperExprOptUntil(TT.Semicolon); } else { break; } } if ((next != (object)MissingExpr)) { exprs.Add(next); } }
public virtual LNode GenerateSwitch(IPGTerminalSet[] branchSets, MSet <int> casesToInclude, LNode[] branchCode, LNode defaultBranch, LNode laVar) { Debug.Assert(branchSets.Length == branchCode.Length); RWList <LNode> stmts = new RWList <LNode>(); for (int i = 0; i < branchSets.Length; i++) { if (casesToInclude.Contains(i)) { foreach (LNode value in GetCases(branchSets[i])) { stmts.Add(F.Call(S.Case, value)); if (stmts.Count > 65535) // sanity check { throw new InvalidOperationException("switch is too large to generate"); } } AddSwitchHandler(branchCode[i], stmts); } } if (!defaultBranch.IsIdNamed(S.Missing)) { stmts.Add(F.Call(S.Label, F.Id(S.Default))); AddSwitchHandler(defaultBranch, stmts); } return(F.Call(S.Switch, (LNode)laVar, F.Braces(stmts.ToRVList()))); }
private RWList <LNode> GenerateExtraMatchingCode(Pair <LNode, string>[] matchingCode, int separateCount, ref Symbol loopType) { var extraMatching = new RWList <LNode>(); if (separateCount != 0) { for (int i = 0; i < matchingCode.Length; i++) { if (matchingCode[i].B != null) // split out this case { var label = F.Id(matchingCode[i].B); // break/continue; matchN: matchingCode[i].A; if (extraMatching.Count > 0) { extraMatching.Add(GetContinueStmt(loopType)); } extraMatching.Add(F.Call(S.Label, label)); extraMatching.Add(matchingCode[i].A); //skipCount++; // put @@{ goto matchN; } in prediction tree matchingCode[i].A = F.Call(S.Goto, label); } } } return(extraMatching); }
public override LNode GenerateMatchExpr(IPGTerminalSet set_, bool savingResult, bool recognizerMode) { var set = (PGIntSet)set_; LNode call; var type = set.ChooseMatchType(2, 4); if (type != PGIntSet.Match.Set) { var args = new RWList <LNode>(); if (type == PGIntSet.Match.Ranges) { // Use MatchRange or MatchExceptRange foreach (var r in set) { if (!set.IsInverted || r.Lo != EOF_int || r.Hi != EOF_int) { args.Add((LNode)set.MakeLiteral(r.Lo)); args.Add((LNode)set.MakeLiteral(r.Hi)); } } var target = recognizerMode ? (set.IsInverted ? _TryMatchExceptRange : _TryMatchRange) : (set.IsInverted ? _MatchExceptRange : _MatchRange); call = ApiCall(target, args); } else { // Use Match or MatchExcept foreach (var r in set) { for (int c = r.Lo; c <= r.Hi; c++) { if (!set.IsInverted || c != EOF_int) { args.Add((LNode)set.MakeLiteral(c)); } } } var target = recognizerMode ? (set.IsInverted ? _TryMatchExcept : _TryMatch) : (set.IsInverted ? _MatchExcept : _Match); call = ApiCall(target, args.ToRVList()); } } else { var setName = GenerateSetDecl(set); if (set.IsInverted) { call = ApiCall(recognizerMode ? _TryMatchExcept : _MatchExcept, F.Id(setName)); } else { call = ApiCall(recognizerMode ? _TryMatch : _Match, F.Id(setName)); } } return(call); }
public static LNode UnpackTuple(LNode node, IMessageSink sink) { var a = node.Args; if (a.Count == 2 && a[0].CallsMin(S.Tuple, 1)) { var output = new RWList <LNode>(); var tuple = a[0].Args; var rhs = a[1]; // Avoid evaluating rhs more than once, if it doesn't look like a simple variable rhs = MaybeAddTempVarDecl(rhs, output); for (int i = 0; i < tuple.Count; i++) { var itemi = F.Dot(rhs, F.Id(GSymbol.Get("Item" + (i + 1)))); if (tuple[i].Calls(S.Var, 2)) { output.Add(F.Var(tuple[i].Args[0], tuple[i].Args[1], itemi)); } else { output.Add(F.Call(S.Assign, tuple[i], itemi)); } } return(F.Call(S.Splice, output.ToRVList())); } return(null); }
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 }; RWList<LNode> output = new RWList<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)); } else output.Add(ctx.Replace(body)); } 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.ToRVList()); }
private void AddSwitchHandler(LNode branch, RWList <LNode> stmts) { stmts.SpliceAdd(branch, S.Splice); if (EndMayBeReachable(branch)) { stmts.Add(F.Call(S.Break)); } }
// Used to avoid evaluating `value` more than once by creating a // temporary variable to hold the value. If `value` looks like a // simple variable, this fn returns value and leaves output unchanged. static LNode MaybeAddTempVarDecl(LNode value, RWList <LNode> output) { if (value.IsCall || char.IsUpper(value.Name.Name.TryGet(0, '\0'))) { LNode tmpId; output.Add(TempVarDecl(value, out tmpId)); return(tmpId); } return(value); }
public static void SpliceAdd(this RWList <LNode> list, LNode node, Symbol listName) { if (node.Calls(listName)) { list.AddRange(node.Args); } else { list.Add(node); } }
private void AddUserAction(LNode action) { int i = _target.Count; _target.SpliceAdd(action, S.Splice); if (action.Range.StartIndex > 0 && _target.Count > i) { if (LLPG.AddCsLineDirectives) { // Remove folder name. This only makes sense if the output // file and input file are in the same folder; sadly we have // no access to the output file name, but as of 2015-05 it's // always true that the output file will be in the same folder. string filename = System.IO.Path.GetFileName(_target[i].Range.Source.FileName); int line = 0; for (; i < _target.Count; i++, line++) { var r = _target[i].Range; if (line != r.Start.Line) { line = r.Start.Line; _target[i] = _target[i].PlusAttr(F.Trivia(S.TriviaRawTextBefore, string.Format("#line {0} {1}\n", line, Ecs.EcsNodePrinter.PrintString(filename, '"')))); } } _target.Add(F.Trivia(S.RawText, "#line default")); } else { _target[i] = _target[i].PlusAttr(F.Trivia(S.TriviaSLCommentBefore, string.Format(" line {0}", _target[i].Range.Start.Line))); } } }
protected virtual Symbol GenerateSetDecl(IPGTerminalSet set) { Symbol setName; if (_setDeclNames.TryGetValue(set, out setName)) { return(setName); } setName = GenerateSetName(_currentRule); _classBody.Add(GenerateSetDecl(set, setName)); return(_setDeclNames[set] = setName); }
public static LNode UnpackTuple(LNode node, IMessageSink sink) { var a = node.Args; if (a.Count == 2 && a[0].CallsMin(S.Tuple, 1)) { var stmts = new RWList <LNode>(); var tuple = a[0].Args; var rhs = a[1]; bool needTemp = rhs.IsCall || !char.IsLower(rhs.Name.Name.TryGet(0, '\0')); if (needTemp) { LNode tmp = F.Id(NextTempName()); stmts.Add(F.Var(F._Missing, tmp.Name, rhs)); rhs = tmp; } for (int i = 0; i < tuple.Count; i++) { stmts.Add(F.Call(S.Assign, tuple[i], F.Dot(rhs, F.Id(GSymbol.Get("Item" + (i + 1)))))); } return(F.Call(S.Splice, stmts.ToRVList())); } return(null); }
protected LNode SingleExprInside(Token group, string stmtType, RWList <LNode> list = null, bool allowUnassignedVarDecl = false) { list = list ?? new RWList <LNode>(); int oldCount = list.Count; AppendExprsInside(group, list, false, allowUnassignedVarDecl); if (list.Count != oldCount + 1) { if (list.Count <= oldCount) { LNode result = F.Id(S.Missing, group.StartIndex + 1, group.StartIndex + 1); list.Add(result); Error(result, "Missing expression inside '{0}'", stmtType); return(result); } else { Error(list[1], "There should be only one expression inside '{0}'", stmtType); list.Resize(oldCount + 1); } } return(list[0]); }
public static LNode @try(LNode node, IMessageSink sink) { if (!node.IsCall) return null; // try(code, catch, Exception::e, handler, catch, ..., finally, handler) // ...becomes... // #try(#{ stmt1; stmt2; ... }, #catch(#var(Exception, e), handler), #finally(handler)) LNode finallyCode = null; RWList<LNode> clauses = new RWList<LNode>(); var parts = node.Args; for (int i = parts.Count-2; i >= 1; i -= 2) { var p = parts[i]; if (p.IsIdNamed(_finally)) { if (clauses.Count != 0 || finallyCode != null) sink.Write(Severity.Error, p, "The «finally» clause must come last, there can only be one of them."); finallyCode = parts[i+1]; } else if (p.Name == _catch) { if (p.ArgCount > 0) { // This is a normal catch clause clauses.Insert(0, F.Call(S.Catch, F.Call(S.Splice, p.Args), parts[i + 1])); } else { // This is a catch-all clause (the type argument is missing) if (clauses.Count != 0) sink.Write(Severity.Error, p, "The catch-all clause must be the last «catch» clause."); clauses.Add(F.Call(S.Catch, F._Missing, parts[i + 1])); } } else if (i > 1 && parts[i-1].IsIdNamed(_catch)) { // This is a normal catch clause clauses.Insert(0, F.Call(S.Catch, AutoRemoveParens(p), parts[i+1])); i--; } else { return Reject(sink, p, "Expected «catch» or «finally» clause here. Clause is missing or malformed."); } if (i == 2) return Reject(sink, parts[1], "Expected «catch» or «finally» clause here. Clause is missing or malformed."); } if (clauses.Count == 0 && finallyCode == null) { Debug.Assert(node.ArgCount <= 1); return Reject(sink, node, "Missing «catch, Type, Code» or «finally, Code» clause"); } if (finallyCode != null) clauses.Add(F.Call(S.Finally, finallyCode)); clauses.Insert(0, node.Args[0]); return node.With(S.Try, clauses.ToRVList()); }
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 }; RWList <LNode> output = new RWList <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)); } } else { output.Add(ctx.Replace(body)); } } 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.ToRVList())); }
protected LNode GeneratePredictionTreeCode(PredictionTree tree, Pair<LNode, string>[] matchingCode, ref Symbol haveLoop) { var braces = F.Braces(); Debug.Assert(tree.Children.Count >= 1); var alts = (Alts)_currentPred; if (tree.Children.Count == 1) return GetPredictionSubtreeCode(tree.Children[0], matchingCode, ref haveLoop); // From the prediction table, we can generate either an if-else chain: // // if (la0 >= '0' && la0 <= '7') sub_tree_1(); // else if (la0 == '-') sub_tree_2(); // else break; // // or a switch statement: // // switch(la0) { // case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': // sub_tree_1(); // break; // case '-': // sub_tree_2(); // break; // default: // goto breakfor; // } // // Assertion levels always need an if-else chain; lookahead levels // consider the complexity of switch vs if and decide which is most // appropriate. Generally "if" is slower, but a switch may require // too many labels since it doesn't support ranges like "la0 >= 'a' // && la0 <= 'z'". // // This class makes if-else chains directly (using IPGTerminalSet. // GenerateTest() to generate the test expressions), but the code // snippet generator (CSG) is used to generate switch statements // because the required code may be more complex. // // We may or may not be generating code inside a for(;;) loop. If we // decide to generate a switch() statement, one of the branches will // usually need to break out of the for loop, but "break" can only // break out of the switch(). In that case, add "stop:" after the // switch() and use "goto stop" instead of "break". RWList<LNode> block = new RWList<LNode>(); LNode laVar = null; MSet<int> switchCases = new MSet<int>(); IPGTerminalSet[] branchSets = null; bool should = false; if (tree.UsesLA()) { laVar = F.Id("la" + tree.Lookahead.ToString()); if (!tree.IsAssertionLevel) { IPGTerminalSet covered = CGH.EmptySet; branchSets = tree.Children.Select(branch => { var set = branch.Set.Subtract(covered); covered = covered.Union(branch.Set); return set; }).ToArray(); should = CGH.ShouldGenerateSwitch(branchSets, switchCases, tree.Children.Last.IsErrorBranch); if (!should) switchCases.Clear(); else if (should && haveLoop == S.For) // Can't "break" out of the for-loop when there is a nested switch, haveLoop = GSymbol.Get(NextStopLabel()); // so use "goto stop". } } LNode[] branchCode = new LNode[tree.Children.Count]; for (int i = 0; i < tree.Children.Count; i++) if (tree.Children[i].IsErrorBranch) { if (alts.ErrorBranch != null && alts.ErrorBranch != DefaultErrorBranch.Value) { Debug.Assert(matchingCode.Length == alts.Arms.Count + 1); branchCode[i] = matchingCode[alts.Arms.Count].A; } else branchCode[i] = CGH.ErrorBranch(tree.TotalCoverage, tree.Lookahead); } else branchCode[i] = GetPredictionSubtreeCode(tree.Children[i], matchingCode, ref haveLoop); var code = GenerateIfElseChain(tree, branchCode, ref laVar, switchCases); if (laVar != null) { block.Insert(0, F.Assign(laVar, CGH.LA(tree.Lookahead))); _laVarsNeeded |= 1ul << tree.Lookahead; } else if (should) laVar = CGH.LA(tree.Lookahead); if (should) { Debug.Assert(switchCases.Count != 0); code = CGH.GenerateSwitch(branchSets, switchCases, branchCode, code, laVar); } block.Add(code); return F.Braces(block.ToRVList()); }
void StmtList(RWList<LNode> list) { TokenType la0; // Line 1719: (~(EOF) => Stmt)* for (;;) { la0 = LA0; if (la0 != EOF) list.Add(Stmt()); else break; } Skip(); }
void ArgList(RWList<LNode> list) { TokenType la0; // Line 1691: nongreedy(ExprOpt (TT.Comma ExprOpt)*)? la0 = LA0; if (la0 == EOF) ; else { list.Add(ExprOpt(true)); // Line 1692: (TT.Comma ExprOpt)* for (;;) { la0 = LA0; if (la0 == TT.Comma) { Skip(); list.Add(ExprOpt(true)); } else if (la0 == EOF) break; else { #line 1693 "EcsParserGrammar.les" Error("Syntax error in argument list"); #line default // Line 1693: (~(EOF|TT.Comma))* for (;;) { la0 = LA0; if (!(la0 == EOF || la0 == TT.Comma)) Skip(); else break; } } } } Skip(); }
LNode BlockCallStmt() { TokenType la0; var id = MatchAny(); Check(Try_BlockCallStmt_Test0(0), "( TT.LParen TT.RParen (TT.LBrace TT.RBrace | TT.Id) | TT.LBrace TT.RBrace | TT.Forward )"); var args = new RWList<LNode>(); LNode block; // Line 1459: ( TT.LParen TT.RParen (BracedBlock | TT.Id => Stmt) | TT.Forward ExprStart TT.Semicolon | BracedBlock ) la0 = LA0; if (la0 == TT.LParen) { var lp = MatchAny(); var rp = Match((int) TT.RParen); #line 1459 "EcsParserGrammar.les" AppendExprsInside(lp, args, false, true); #line default // Line 1460: (BracedBlock | TT.Id => Stmt) la0 = LA0; if (la0 == TT.LBrace) block = BracedBlock(); else { block = Stmt(); #line 1463 "EcsParserGrammar.les" if ((ColumnOf(block.Range.StartIndex) <= ColumnOf(id.StartIndex) || !char.IsLower(id.Value.ToString().FirstOrDefault()))) { ErrorSink.Write(_Warning, block, "Probable missing semicolon before this statement."); } #line default } } else if (la0 == TT.Forward) { var fwd = MatchAny(); var e = ExprStart(true); Match((int) TT.Semicolon); #line 1470 "EcsParserGrammar.les" block = SetOperatorStyle(F.Call(S.Forward, e, fwd.StartIndex, e.Range.EndIndex)); #line default } else block = BracedBlock(); #line 1474 "EcsParserGrammar.les" args.Add(block); var result = F.Call((Symbol) id.Value, args.ToRVList(), id.StartIndex, block.Range.EndIndex); if (block.Calls(S.Forward, 1)) { result = F.Attr(_triviaForwardedProperty, result); } #line 1479 "EcsParserGrammar.les" return SetBaseStyle(result, NodeStyle.Special); #line default }
int WordAttributes(ref RWList<LNode> attrs) { TokenType la0; #line 914 "EcsParserGrammar.les" TokenType LA1; int nonKeywords = 0; if (LA0 == TT.Id && ((LA1 = LA(1)) == TT.Set || LA1 == TT.LParen || LA1 == TT.Dot)) return 0; #line 918 "EcsParserGrammar.les" Token t; #line default // Line 920: (TT.AttrKeyword | ((@`.`(TT, noMacro(@this))|TT.@new|TT.Id) | UnusualId) &(( DataType ((TT.AttrKeyword|TT.Id|TT.TypeKeyword) | UnusualId) | (TT.@new|TT.AttrKeyword) | @`.`(TT, noMacro(@this)) | TT.@checked TT.LBrace TT.RBrace | TT.@unchecked TT.LBrace TT.RBrace | @`.`(TT, noMacro(@default)) TT.Colon | TT.@using TT.LParen | (@`.`(TT, noMacro(@break))|@`.`(TT, noMacro(@continue))|@`.`(TT, noMacro(@return))|@`.`(TT, noMacro(@throw))|TT.@case|TT.@class|TT.@delegate|TT.@do|TT.@enum|TT.@event|TT.@fixed|TT.@for|TT.@foreach|TT.@goto|TT.@interface|TT.@lock|TT.@namespace|TT.@struct|TT.@switch|TT.@try|TT.@while) )))* for (;;) { switch (LA0) { case TT.AttrKeyword: { t = MatchAny(); #line 920 "EcsParserGrammar.les" attrs.Add(IdNode(t)); #line default } break; case TT.@this: case TT.@new: case TT.ContextualKeyword: case TT.Id: { if (Try_WordAttributes_Test0(1)) { // Line 921: ((@`.`(TT, noMacro(@this))|TT.@new|TT.Id) | UnusualId) la0 = LA0; if (la0 == TT.@this || la0 == TT.@new || la0 == TT.Id) t = MatchAny(); else t = UnusualId(); #line 934 "EcsParserGrammar.les" LNode node; if ((t.Type() == TT.@new || t.Type() == TT.@this)) { node = IdNode(t); } else { node = F.Attr(_triviaWordAttribute, F.Id("#" + t.Value.ToString(), t.StartIndex, t.EndIndex)); } #line 940 "EcsParserGrammar.les" attrs = attrs ?? new RWList<LNode>(); attrs.Add(node); nonKeywords++; #line default } else goto stop; } break; default: goto stop; } } stop:; #line 945 "EcsParserGrammar.les" return nonKeywords; #line default }
private void AddSwitchHandler(LNode branch, RWList<LNode> stmts) { stmts.SpliceAdd(branch, S.Splice); if (EndMayBeReachable(branch)) stmts.Add(F.Call(S.Break)); }
public static LNode QuoteOne(LNode node, bool substitutions = true) { LNode result; switch (node.Kind) { case LNodeKind.Literal: // => F.Literal(value) result = F.Call(F_Literal, node.WithoutAttrs()); break; case LNodeKind.Id: // => F.Id(string), F.Id(CodeSymbols.Name) result = F.Call(F_Id, QuoteIdHelper(node.Name)); break; default: // NodeKind.Call => F.Dot(...), F.Of(...), F.Call(...), F.Braces(...) if (substitutions && node.Calls(S.Substitute, 1)) { result = node.Args[0]; } else if (node.Calls(S.Braces)) // F.Braces(...) { result = F.Call(F_Braces, node.Args.SmartSelect(arg => QuoteOne(arg))); } else if (node.Calls(S.Dot) && node.ArgCount.IsInRange(1, 2)) { result = F.Call(F_Dot, node.Args.SmartSelect(arg => QuoteOne(arg))); } else if (node.Calls(S.Of)) { result = F.Call(F_Of, node.Args.SmartSelect(arg => QuoteOne(arg))); } else // General case: F.Call(<Target>, <Args>) { LNode outTarget; if (node.Target.IsId) { outTarget = QuoteIdHelper(node.Name); } else { outTarget = QuoteOne(node.Target); } RVList <LNode> outArgs = new RVList <LNode>(outTarget); foreach (LNode arg in node.Args) { outArgs.Add(QuoteOne(arg)); } result = F.Call(F_Call, outArgs); } break; } // Translate attributes too (if any) RWList <LNode> outAttrs = null; foreach (LNode attr in node.Attrs) { if (!attr.IsTrivia) { outAttrs = outAttrs ?? new RWList <LNode>(); outAttrs.Add(QuoteOne(attr)); } } if (outAttrs != null) { result = F.Call(F.Dot(result, Id_WithAttrs), outAttrs.ToRVList()); } return(result); }
public void StmtList(ref RWList<LNode> exprs) { TT la0; // line 192 exprs = exprs ?? new RWList<LNode>(); var next = SuperExprOptUntil(TT.Semicolon); // Line 194: (TT.Semicolon SuperExprOptUntil)* for (;;) { la0 = (TT) LA0; if (la0 == TT.Semicolon) { // line 194 exprs.Add(next); Skip(); next = SuperExprOptUntil(TT.Semicolon); } else break; } // line 198 if ((next != (object) MissingExpr)) exprs.Add(next); }
protected void ExprList(ref RWList<LNode> exprs) { TT la0; // line 166 exprs = exprs ?? new RWList<LNode>(); // Line 167: (SuperExpr (TT.Comma SuperExprOpt)* | TT.Comma SuperExprOpt (TT.Comma SuperExprOpt)*)? switch ((TT) LA0) { case TT.Assignment: case TT.At: case TT.BQString: case TT.Colon: case TT.Dot: case TT.Id: case TT.LBrace: case TT.LBrack: case TT.LParen: case TT.NormalOp: case TT.Not: case TT.Number: case TT.OtherLit: case TT.PrefixOp: case TT.PreSufOp: case TT.SQString: case TT.String: case TT.Symbol: { exprs.Add(SuperExpr()); // Line 168: (TT.Comma SuperExprOpt)* for (;;) { la0 = (TT) LA0; if (la0 == TT.Comma) { Skip(); exprs.Add(SuperExprOpt()); } else break; } } break; case TT.Comma: { // line 169 exprs.Add(MissingExpr); Skip(); exprs.Add(SuperExprOpt()); // Line 170: (TT.Comma SuperExprOpt)* for (;;) { la0 = (TT) LA0; if (la0 == TT.Comma) { Skip(); exprs.Add(SuperExprOpt()); } else break; } } break; } }
protected void ExprList(ref RWList <LNode> exprs) { TT la0; exprs = exprs ?? new RWList <LNode>(); // Line 160: (SuperExpr (TT.Comma SuperExprOpt)* | TT.Comma SuperExprOpt (TT.Comma SuperExprOpt)*)? switch (LA0) { case TT.Assignment: case TT.At: case TT.BQString: case TT.Colon: case TT.Dot: case TT.Id: case TT.LBrace: case TT.LBrack: case TT.LParen: case TT.NormalOp: case TT.Not: case TT.Number: case TT.OtherLit: case TT.PrefixOp: case TT.PreSufOp: case TT.SQString: case TT.String: case TT.Symbol: { exprs.Add(SuperExpr()); // Line 161: (TT.Comma SuperExprOpt)* for (;;) { la0 = LA0; if (la0 == TT.Comma) { Skip(); exprs.Add(SuperExprOpt()); } else { break; } } } break; case TT.Comma: { exprs.Add(MissingExpr); Skip(); exprs.Add(SuperExprOpt()); // Line 163: (TT.Comma SuperExprOpt)* for (;;) { la0 = LA0; if (la0 == TT.Comma) { Skip(); exprs.Add(SuperExprOpt()); } else { break; } } } break; } }
public override LNode GenerateMatchExpr(IPGTerminalSet set_, bool savingResult, bool recognizerMode) { var set = (PGIntSet)set_; LNode call; var type = set.ChooseMatchType(2, 4); if (type != PGIntSet.Match.Set) { var args = new RWList<LNode>(); if (type == PGIntSet.Match.Ranges) { // Use MatchRange or MatchExceptRange foreach (var r in set) { if (!set.IsInverted || r.Lo != EOF_int || r.Hi != EOF_int) { args.Add((LNode)set.MakeLiteral(r.Lo)); args.Add((LNode)set.MakeLiteral(r.Hi)); } } var target = recognizerMode ? (set.IsInverted ? _TryMatchExceptRange : _TryMatchRange) : (set.IsInverted ? _MatchExceptRange : _MatchRange); call = ApiCall(target, args); } else { // Use Match or MatchExcept foreach (var r in set) { for (int c = r.Lo; c <= r.Hi; c++) { if (!set.IsInverted || c != EOF_int) args.Add((LNode)set.MakeLiteral(c)); } } var target = recognizerMode ? (set.IsInverted ? _TryMatchExcept : _TryMatch) : (set.IsInverted ? _MatchExcept : _Match); call = ApiCall(target, args.ToRVList()); } } else { var setName = GenerateSetDecl(set); if (set.IsInverted) call = ApiCall(recognizerMode ? _TryMatchExcept : _MatchExcept, F.Id(setName)); else call = ApiCall(recognizerMode ? _TryMatch : _Match, F.Id(setName)); } return call; }
private void MakeTestExpr(LNode pattern, LNode candidate, out Symbol varArgSym, out LNode varArgCond) { varArgSym = null; varArgCond = null; LNode condition; bool isParams, refExistingVar; var nodeVar = GetSubstitutionVar(pattern, out condition, out isParams, out refExistingVar); 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); 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.Neq, 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"))), 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"))), LNode.Literal(null))).SetStyle(NodeStyle.Operator)); } else { Tests.Add(LNode.Call(LNode.Call(CodeSymbols.Dot, LNode.List(pattern, LNode.Id((Symbol)"Equals"))), LNode.List(LNode.Call(CodeSymbols.Dot, LNode.List(candidate, LNode.Id((Symbol)"Value")))))); } } else { int?varArgAt; int fixedArgC = GetFixedArgCount(pattern.Args, out varArgAt); 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"))), LNode.List(quoteTarget)); } else if (varArgAt.HasValue) { targetTest = LNode.Call(LNode.Call(CodeSymbols.Dot, LNode.List(candidate, LNode.Id((Symbol)"CallsMin"))), LNode.List(quoteTarget, F.Literal(fixedArgC))); } else { targetTest = LNode.Call(LNode.Call(CodeSymbols.Dot, LNode.List(candidate, LNode.Id((Symbol)"Calls"))), 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")))); 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"))), LNode.Id((Symbol)"Count"))), 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"))), LNode.Id((Symbol)"Count"))), F.Literal(fixedArgC)))); } int i = Tests.Count; MakeTestExpr(pTarget, LNode.Call(CodeSymbols.Dot, LNode.List(candidate, LNode.Id((Symbol)"Target")))); } MakeArgListTests(pattern.Args, ref candidate); } }
LNode NewExpr() { TokenType la0, la1; #line 419 "EcsParserGrammar.les" Token? majorDimension = null; int endIndex; var list = new RWList<LNode>(); #line default var op = Match((int) TT.@new); // Line 425: ( &{(count = CountDims(LT($LI), @false)) > 0} TT.LBrack TT.RBrack TT.LBrace TT.RBrace | TT.LBrace TT.RBrace | DataType (TT.LParen TT.RParen (TT.LBrace TT.RBrace)? / (TT.LBrace TT.RBrace)?) ) la0 = LA0; if (la0 == TT.LBrack) { Check((count = CountDims(LT(0), false)) > 0, "(count = CountDims(LT($LI), @false)) > 0"); var lb = MatchAny(); var rb = Match((int) TT.RBrack); #line 427 "EcsParserGrammar.les" var type = F.Id(S.GetArrayKeyword(count), lb.StartIndex, rb.EndIndex); #line default lb = Match((int) TT.LBrace); rb = Match((int) TT.RBrace); #line 430 "EcsParserGrammar.les" list.Add(LNode.Call(type, type.Range)); AppendInitializersInside(lb, list); endIndex = rb.EndIndex; #line default } else if (la0 == TT.LBrace) { var lb = MatchAny(); var rb = Match((int) TT.RBrace); #line 437 "EcsParserGrammar.les" list.Add(F._Missing); AppendInitializersInside(lb, list); endIndex = rb.EndIndex; #line default } else { var type = DataType(false, out majorDimension); // Line 449: (TT.LParen TT.RParen (TT.LBrace TT.RBrace)? / (TT.LBrace TT.RBrace)?) do { la0 = LA0; if (la0 == TT.LParen) { la1 = LA(1); if (la1 == TT.RParen) { var lp = MatchAny(); var rp = MatchAny(); #line 451 "EcsParserGrammar.les" if ((majorDimension != null)) { Error("Syntax error: unexpected constructor argument list (...)"); } #line 454 "EcsParserGrammar.les" list.Add(F.Call(type, ExprListInside(lp).ToRVList(), type.Range.StartIndex, rp.EndIndex)); endIndex = rp.EndIndex; #line default // Line 457: (TT.LBrace TT.RBrace)? la0 = LA0; if (la0 == TT.LBrace) { la1 = LA(1); if (la1 == TT.RBrace) { var lb = MatchAny(); var rb = MatchAny(); #line 459 "EcsParserGrammar.les" AppendInitializersInside(lb, list); endIndex = rb.EndIndex; #line default } } } else goto match2; } else goto match2; break; match2: { #line 466 "EcsParserGrammar.les" Token lb = op, rb = op; #line 466 "EcsParserGrammar.les" bool haveBraces = false; #line default // Line 467: (TT.LBrace TT.RBrace)? la0 = LA0; if (la0 == TT.LBrace) { la1 = LA(1); if (la1 == TT.RBrace) { lb = MatchAny(); rb = MatchAny(); #line 467 "EcsParserGrammar.les" haveBraces = true; #line default } } #line 469 "EcsParserGrammar.les" if ((majorDimension != null)) { list.Add(LNode.Call(type, ExprListInside(majorDimension.Value).ToRVList(), type.Range)); } else { list.Add(LNode.Call(type, type.Range)); } #line 474 "EcsParserGrammar.les" if ((haveBraces)) { AppendInitializersInside(lb, list); endIndex = rb.EndIndex; } else { endIndex = type.Range.EndIndex; } #line 480 "EcsParserGrammar.les" if ((!haveBraces && majorDimension == null)) { if (IsArrayType(type)) { Error("Syntax error: missing array size expression"); } else { Error("Syntax error: expected constructor argument list (...) or initializers {...}"); } } #line default } } while (false); } #line 490 "EcsParserGrammar.les" return F.Call(S.New, list.ToRVList(), op.StartIndex, endIndex); #line default }
private void Add(Properties.Property property) { propertyByName[property.name] = property; properties.Add(property); }
void TParams(ref LNode r) { TokenType la0; RWList<LNode> list = new RWList<LNode> { r }; Token end; // Line 195: ( TT.LT (DataType (TT.Comma DataType)*)? TT.GT | TT.Dot TT.LBrack TT.RBrack | TT.Not TT.LParen TT.RParen ) la0 = LA0; if (la0 == TT.LT) { Skip(); // Line 195: (DataType (TT.Comma DataType)*)? switch (LA0) { case TT.@operator: case TT.ContextualKeyword: case TT.Id: case TT.Substitute: case TT.TypeKeyword: { list.Add(DataType()); // Line 195: (TT.Comma DataType)* for (;;) { la0 = LA0; if (la0 == TT.Comma) { Skip(); list.Add(DataType()); } else break; } } break; } end = Match((int) TT.GT); } else if (la0 == TT.Dot) { Skip(); var t = Match((int) TT.LBrack); end = Match((int) TT.RBrack); #line 196 "EcsParserGrammar.les" list = AppendExprsInside(t, list); #line default } else { Match((int) TT.Not); var t = Match((int) TT.LParen); end = Match((int) TT.RParen); #line 197 "EcsParserGrammar.les" list = AppendExprsInside(t, list); #line default } #line 200 "EcsParserGrammar.les" int start = r.Range.StartIndex; r = F.Call(S.Of, list.ToRVList(), start, end.EndIndex); #line default }
public override void Reset() { value.Clear(); value.Add(new IntInfo(defaultValue, null)); }
void ExprList(RWList<LNode> list, bool allowTrailingComma = false, bool allowUnassignedVarDecl = false) { TokenType la0, la1; // Line 1682: nongreedy(ExprOpt (TT.Comma &{allowTrailingComma} EOF / TT.Comma ExprOpt)*)? la0 = LA0; if (la0 == EOF) ; else { list.Add(ExprOpt(allowUnassignedVarDecl)); // Line 1683: (TT.Comma &{allowTrailingComma} EOF / TT.Comma ExprOpt)* for (;;) { la0 = LA0; if (la0 == TT.Comma) { la1 = LA(1); if (la1 == EOF) { if (allowTrailingComma) { Skip(); Skip(); } else goto match2; } else if (ExprList_set0.Contains((int) la1)) goto match2; else goto error; } else if (la0 == EOF) break; else goto error; continue; match2: { Skip(); list.Add(ExprOpt(allowUnassignedVarDecl)); } continue; error: { #line 1685 "EcsParserGrammar.les" Error("Syntax error in expression list"); #line default // Line 1685: (~(EOF|TT.Comma))* for (;;) { la0 = LA0; if (!(la0 == EOF || la0 == TT.Comma)) Skip(); else break; } } } } Skip(); }
protected LNode GeneratePredictionTreeCode(PredictionTree tree, Pair <LNode, string>[] matchingCode, ref Symbol haveLoop) { var braces = F.Braces(); Debug.Assert(tree.Children.Count >= 1); var alts = (Alts)_currentPred; if (tree.Children.Count == 1) { return(GetPredictionSubtreeCode(tree.Children[0], matchingCode, ref haveLoop)); } // From the prediction table, we can generate either an if-else chain: // // if (la0 >= '0' && la0 <= '7') sub_tree_1(); // else if (la0 == '-') sub_tree_2(); // else break; // // or a switch statement: // // switch(la0) { // case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': // sub_tree_1(); // break; // case '-': // sub_tree_2(); // break; // default: // goto breakfor; // } // // Assertion levels always need an if-else chain; lookahead levels // consider the complexity of switch vs if and decide which is most // appropriate. Generally "if" is slower, but a switch may require // too many labels since it doesn't support ranges like "la0 >= 'a' // && la0 <= 'z'". // // This class makes if-else chains directly (using IPGTerminalSet. // GenerateTest() to generate the test expressions), but the code // snippet generator (CSG) is used to generate switch statements // because the required code may be more complex. // // We may or may not be generating code inside a for(;;) loop. If we // decide to generate a switch() statement, one of the branches will // usually need to break out of the for loop, but "break" can only // break out of the switch(). In that case, add "stop:" after the // switch() and use "goto stop" instead of "break". RWList <LNode> block = new RWList <LNode>(); LNode laVar = null; MSet <int> switchCases = new MSet <int>(); IPGTerminalSet[] branchSets = null; bool should = false; if (tree.UsesLA()) { laVar = F.Id("la" + tree.Lookahead.ToString()); if (!tree.IsAssertionLevel) { IPGTerminalSet covered = CGH.EmptySet; branchSets = tree.Children.Select(branch => { var set = branch.Set.Subtract(covered); covered = covered.Union(branch.Set); return(set); }).ToArray(); should = CGH.ShouldGenerateSwitch(branchSets, switchCases, tree.Children.Last.IsErrorBranch); if (!should) { switchCases.Clear(); } else if (should && haveLoop == S.For) { // Can't "break" out of the for-loop when there is a nested switch, haveLoop = GSymbol.Get(NextStopLabel()); // so use "goto stop". } } } LNode[] branchCode = new LNode[tree.Children.Count]; for (int i = 0; i < tree.Children.Count; i++) { if (tree.Children[i].IsErrorBranch) { if (alts.ErrorBranch != null && alts.ErrorBranch != DefaultErrorBranch.Value) { Debug.Assert(matchingCode.Length == alts.Arms.Count + 1); branchCode[i] = matchingCode[alts.Arms.Count].A; } else { branchCode[i] = CGH.ErrorBranch(tree.TotalCoverage, tree.Lookahead); } } else { branchCode[i] = GetPredictionSubtreeCode(tree.Children[i], matchingCode, ref haveLoop); } } var code = GenerateIfElseChain(tree, branchCode, ref laVar, switchCases); if (laVar != null) { block.Insert(0, F.Assign(laVar, CGH.LA(tree.Lookahead))); _laVarsNeeded |= 1ul << tree.Lookahead; } else if (should) { laVar = CGH.LA(tree.Lookahead); } if (should) { Debug.Assert(switchCases.Count != 0); code = CGH.GenerateSwitch(branchSets, switchCases, branchCode, code, laVar); } block.Add(code); return(F.Braces(block.ToRVList())); }
void InitializerList(RWList<LNode> list) { TokenType la0, la1; // Line 1711: nongreedy(InitializerExpr (TT.Comma EOF / TT.Comma InitializerExpr)*)? la0 = LA0; if (la0 == EOF) ; else { list.Add(InitializerExpr()); // Line 1712: (TT.Comma EOF / TT.Comma InitializerExpr)* for (;;) { la0 = LA0; if (la0 == TT.Comma) { la1 = LA(1); if (la1 == EOF) { Skip(); Skip(); } else if (ExprList_set0.Contains((int) la1)) { Skip(); list.Add(InitializerExpr()); } else goto error; } else if (la0 == EOF) break; else goto error; continue; error: { #line 1714 "EcsParserGrammar.les" Error("Syntax error in initializer list"); #line default // Line 1714: (~(EOF|TT.Comma))* for (;;) { la0 = LA0; if (!(la0 == EOF || la0 == TT.Comma)) Skip(); else break; } } } } Skip(); }
public static LNode UnpackTuple(LNode node, IMessageSink sink) { var a = node.Args; if (a.Count == 2 && a[0].CallsMin(S.Tuple, 1)) { var stmts = new RWList<LNode>(); var tuple = a[0].Args; var rhs = a[1]; bool needTemp = rhs.IsCall || !char.IsLower(rhs.Name.Name.TryGet(0, '\0')); if (needTemp) { LNode tmp = F.Id(NextTempName()); stmts.Add(F.Var(F._Missing, tmp.Name, rhs)); rhs = tmp; } for (int i = 0; i < tuple.Count; i++) stmts.Add(F.Call(S.Assign, tuple[i], F.Dot(rhs, F.Id(GSymbol.Get("Item" + (i + 1)))))); return F.Call(S.Splice, stmts.ToRVList()); } return null; }
[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); RVList<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 RWList<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, Range.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) "RVList"), LNode.Id((Symbol) "LNode"))); output.Add(F.Call(S.Var, Range.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.ToRVList()); } }
private RWList<LNode> GenerateExtraMatchingCode(Pair<LNode, string>[] matchingCode, int separateCount, ref Symbol loopType) { var extraMatching = new RWList<LNode>(); if (separateCount != 0) { for (int i = 0; i < matchingCode.Length; i++) { if (matchingCode[i].B != null) // split out this case { var label = F.Id(matchingCode[i].B); // break/continue; matchN: matchingCode[i].A; if (extraMatching.Count > 0) extraMatching.Add(GetContinueStmt(loopType)); extraMatching.Add(F.Call(S.Label, label)); extraMatching.Add(matchingCode[i].A); //skipCount++; // put @@{ goto matchN; } in prediction tree matchingCode[i].A = F.Call(S.Goto, label); } } } return extraMatching; }
public virtual LNode GenerateSwitch(IPGTerminalSet[] branchSets, MSet<int> casesToInclude, LNode[] branchCode, LNode defaultBranch, LNode laVar) { Debug.Assert(branchSets.Length == branchCode.Length); RWList<LNode> stmts = new RWList<LNode>(); for (int i = 0; i < branchSets.Length; i++) { if (casesToInclude.Contains(i)) { foreach (LNode value in GetCases(branchSets[i])) { stmts.Add(F.Call(S.Case, value)); if (stmts.Count > 65535) // sanity check throw new InvalidOperationException("switch is too large to generate"); } AddSwitchHandler(branchCode[i], stmts); } } if (!defaultBranch.IsIdNamed(S.Missing)) { stmts.Add(F.Call(S.Label, F.Id(S.Default))); AddSwitchHandler(defaultBranch, stmts); } return F.Call(S.Switch, (LNode)laVar, F.Braces(stmts.ToRVList())); }
// Used to avoid evaluating `value` more than once by creating a // temporary variable to hold the value. If `value` looks like a // simple variable, this fn returns value and leaves output unchanged. static LNode MaybeAddTempVarDecl(LNode value, RWList<LNode> output) { if (value.IsCall || char.IsUpper(value.Name.Name.TryGet(0, '\0'))) { LNode tmpId; output.Add(TempVarDecl(value, out tmpId)); return tmpId; } return value; }
public static LNode UnpackTuple(LNode node, IMessageSink sink) { var a = node.Args; if (a.Count == 2 && a[0].CallsMin(S.Tuple, 1)) { var output = new RWList<LNode>(); var tuple = a[0].Args; var rhs = a[1]; // Avoid evaluating rhs more than once, if it doesn't look like a simple variable rhs = MaybeAddTempVarDecl(rhs, output); for (int i = 0; i < tuple.Count; i++) { var itemi = F.Dot(rhs, F.Id(GSymbol.Get("Item" + (i + 1)))); if (tuple[i].Calls(S.Var, 2)) output.Add(F.Var(tuple[i].Args[0], tuple[i].Args[1], itemi)); else output.Add(F.Call(S.Assign, tuple[i], itemi)); } return F.Call(S.Splice, output.ToRVList()); } return null; }
[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); RVList <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 RWList <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, Range.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)"RVList"), LNode.Id((Symbol)"LNode"))); output.Add(F.Call(S.Var, Range.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.ToRVList())); } }