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 virtual void Done() { _classBody = null; F = null; _setDeclNames = null; _currentRule = null; }
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 void Generate(Rule rule) { CGH.BeginRule(rule); _currentRule = rule; _target = new RWList<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 = CGH.CreateTryWrapperForRecognizer(rule); _classBody.SpliceAdd(method, S.Splice); } method = CGH.CreateRuleMethod(rule, _target.ToRVList()); _classBody.SpliceAdd(method, S.Splice); }
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 IListAndListSource <LNode> ParseExprs() { var list = new RWList <LNode>(); ExprList(ref list); return(list); }
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 AddSwitchHandler(LNode branch, RWList <LNode> stmts) { stmts.SpliceAdd(branch, S.Splice); if (EndMayBeReachable(branch)) { stmts.Add(F.Call(S.Break)); } }
void VisitWithNewTarget(Pred toBeVisited, RWList <LNode> target) { var old = _target; _target = target; Visit(toBeVisited); _target = old; }
protected RWList <LNode> AppendInitializersInside(Token group, RWList <LNode> list) { if (Down(group.Children)) { InitializerList(list); return(Up(list)); } return(list); }
protected RWList <LNode> AppendExprsInside(Token group, RWList <LNode> list, bool allowTrailingComma = false, bool allowUnassignedVarDecl = false) { if (Down(group.Children)) { ExprList(list, allowTrailingComma, allowUnassignedVarDecl); return(Up(list)); } return(list); }
public IListSource <LNode> ParseExprs() { var list = new RWList <LNode>(); try { ExprList(list); } catch (Exception ex) { UnhandledException(ex); } return(list); }
public IListSource <LNode> ParseStmtsGreedy() { var list = new RWList <LNode>(); try { StmtList(list); } catch (Exception ex) { UnhandledException(ex); } return(list); }
protected RWList <LNode> AppendExprsInside(Token group, RWList <LNode> list) { if (Down(group.Children)) { ExprList(ref list); return(Up(list)); } return(list); }
protected RWList <LNode> AppendStmtsInside(Token group, RWList <LNode> list) { if (Down(group.Children)) { StmtList(list); return(Up(list)); } return(list); }
// Restructures an RVList if it has degraded severely. Time: O(Count) void AutoOptimize <T>(ref RVList <T> v) { // Check if the chain length substantially exceeds Sqrt(v.Count) if ((v.BlockChainLength - 10) * (v.BlockChainLength - 10) > v.Count) { RWList <T> w = v.ToRWList(); // This is basically a no-op w[0] = w[0]; // Restructure & make mutable v = w.ToRVList(); // Mark immutable again } }
// 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 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()); }
public LNode Vars(LNode type, params LNode[] namesWithValues) { type = type ?? _Missing; var list = new RWList <LNode>() { type }; list.AddRange(namesWithValues); return(Call(S.Var, list.ToRVList())); }
public static void SpliceInsert(this RWList <LNode> list, int index, LNode node, Symbol listName) { if (node.Calls(listName)) { list.InsertRange(index, node.Args); } else { list.Insert(index, node); } }
public static void SpliceAdd(this RWList <LNode> list, LNode node, Symbol listName) { if (node.Calls(listName)) { list.AddRange(node.Args); } else { list.Add(node); } }
protected virtual LNode ParseBraces(Token t, int endIndex) { RWList <LNode> list = new RWList <LNode>(); if (Down(t.Children)) { StmtList(ref list); Up(); } return(F.Braces(list.ToRVList(), t.StartIndex, endIndex)); }
Mode = MacroMode.ProcessChildrenBefore)] // post-normal-macro-expansion public static LNode with(LNode fn, IMessageSink sink) { LNode braces; if (fn.ArgCount != 2 || !(braces = fn.Args[1]).Calls(S.Braces)) { return(null); } LNode tmp = F.Id(NextTempName()); RWList <LNode> stmts = braces.Args.ToRWList(); stmts = stmts.SmartSelect(stmt => stmt.FindAndReplace(expr => { if (expr.Calls(S.Dot, 1)) { return(expr.WithArgs(new RVList <LNode>(tmp, expr.Args.Last))); } return(null); })); stmts.Insert(0, F.Var(null, tmp.Name, fn.Args[0])); return(F.Braces(stmts.ToRVList())); }
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 void Generate(Rule rule) { CGH.BeginRule(rule); _currentRule = rule; _target = new RWList <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 = CGH.CreateTryWrapperForRecognizer(rule); _classBody.SpliceAdd(method, S.Splice); } method = CGH.CreateRuleMethod(rule, _target.ToRVList()); _classBody.SpliceAdd(method, S.Splice); }
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); }
private void AddSwitchHandler(LNode branch, RWList<LNode> stmts) { stmts.SpliceAdd(branch, S.Splice); if (EndMayBeReachable(branch)) stmts.Add(F.Call(S.Break)); }
LNode Atom(Precedence context, ref RWList<LNode> attrs) { TT la0, la1; // line 39 LNode e = MissingExpr; LNode _; // Line 41: ( (TT.Id (&{t.EndIndex == LT($LI).StartIndex && context.CanParse(P.Primary)} TT.LParen TT.RParen / ) | (TT.Number|TT.OtherLit|TT.SQString|TT.String|TT.Symbol) | TT.At TT.LBrack TT.RBrack | (TT.PrefixOp|TT.PreSufOp) Expr) | (TT.Colon TT.Indent TT.Dedent greedy(TT.Colon)? / &{context != P.SuperExpr} (TT.Assignment|TT.BQString|TT.Colon|TT.Dot|TT.NormalOp|TT.Not) Expr) | TT.LBrack TT.RBrack Atom | TT.LParen TT.RParen | TT.LBrace TT.RBrace ) do { switch ((TT) LA0) { case TT.Id: { var t = MatchAny(); // Line 42: (&{t.EndIndex == LT($LI).StartIndex && context.CanParse(P.Primary)} TT.LParen TT.RParen / ) la0 = (TT) LA0; if (la0 == TT.LParen) { if (t.EndIndex == LT(0).StartIndex && context.CanParse(P.Primary)) { la1 = (TT) LA(1); if (la1 == TT.RParen) { var p = MatchAny(); var rp = MatchAny(); // line 44 e = ParseCall(t, p, rp.EndIndex); } else // line 45 e = F.Id((Symbol) t.Value, t.StartIndex, t.EndIndex); } else // line 45 e = F.Id((Symbol) t.Value, t.StartIndex, t.EndIndex); } else // line 45 e = F.Id((Symbol) t.Value, t.StartIndex, t.EndIndex); } break; case TT.Number: case TT.OtherLit: case TT.SQString: case TT.String: case TT.Symbol: { var t = MatchAny(); // line 49 e = F.Literal(t.Value, t.StartIndex, t.EndIndex); } break; case TT.At: { Skip(); var t = Match((int) TT.LBrack); var rb = Match((int) TT.RBrack); // line 52 e = F.Literal(t.Children, t.StartIndex, rb.EndIndex); } break; case TT.PrefixOp: case TT.PreSufOp: { var t = MatchAny(); e = Expr(PrefixPrecedenceOf(t), out _); e = F.Call((Symbol) t.Value, e, t.StartIndex, e.Range.EndIndex); e.BaseStyle = NodeStyle.Operator; } break; case TT.Colon: { if (context != P.SuperExpr) { switch ((TT) LA(1)) { case TT.Indent: goto match5; 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: goto match6; default: goto error; } } else goto match5; } case TT.Assignment: case TT.BQString: case TT.Dot: case TT.NormalOp: case TT.Not: goto match6; case TT.LBrack: { var t = MatchAny(); Match((int) TT.RBrack); // line 69 attrs = AppendExprsInside(t, attrs); e = Atom(context, ref attrs); } break; case TT.LParen: { var t = MatchAny(); var rp = Match((int) TT.RParen); // line 72 e = ParseParens(t, rp.EndIndex); } break; case TT.LBrace: { var t = MatchAny(); var rb = Match((int) TT.RBrace); // line 74 e = ParseBraces(t, rb.EndIndex); } break; default: goto error; } break; match5: { Skip(); var t = Match((int) TT.Indent); var rb = Match((int) TT.Dedent); // Line 59: greedy(TT.Colon)? la0 = (TT) LA0; if (la0 == TT.Colon) Skip(); // line 60 e = ParseBraces(t, rb.EndIndex); } break; match6: { Check(context != P.SuperExpr, "context != P.SuperExpr"); var t = MatchAny(); e = Expr(PrefixPrecedenceOf(t), out _); e = F.Call((Symbol) t.Value, e, t.StartIndex, e.Range.EndIndex); e.BaseStyle = NodeStyle.Operator; } break; error: { // line 76 e = F.Id(S.Missing, LT0.StartIndex, LT0.StartIndex); Error(0, "Expected an expression here"); } } while (false); // line 80 return e; }
void StmtList(RWList<LNode> list) { TokenType la0; // Line 1719: (~(EOF) => Stmt)* for (;;) { la0 = LA0; if (la0 != EOF) list.Add(Stmt()); 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())); }
LNode DoStmt(int startIndex) { Skip(); var block = Stmt(); Match((int) TT.@while); var p = Match((int) TT.LParen); Match((int) TT.RParen); var end = Match((int) TT.Semicolon); #line 1531 "EcsParserGrammar.les" var parts = new RWList<LNode> { block }; SingleExprInside(p, "while (...)", parts); return F.Call(S.DoWhile, parts.ToRVList(), startIndex, end.EndIndex); #line default }
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(); }
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()); }
LNode AssemblyOrModuleAttribute(int startIndex, RVList<LNode> attrs) { Check(Down(0) && Up(Try_Scan_AsmOrModLabel(0)), "Down($LI) && Up(Try_Scan_AsmOrModLabel(0))"); var lb = MatchAny(); var rb = Match((int) TT.RBrack); #line 1226 "EcsParserGrammar.les" Down(lb); #line default var kind = AsmOrModLabel(); #line 1228 "EcsParserGrammar.les" var list = new RWList<LNode>(); #line default ExprList(list); #line 1231 "EcsParserGrammar.les" Up(); var r = F.Call(kind.Value == _module ? S.Module : S.Assembly, list.ToRVList(), startIndex, rb.EndIndex); return r.WithAttrs(attrs); #line default }
[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()); } }
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); }
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())); }
LNode PrimaryExpr() { TokenType la1; var e = Atom(); // Line 506: greedy( (TT.ColonColon|TT.Dot|TT.PtrArrow|TT.QuickBind) Atom / PrimaryExpr_NewStyleCast / TT.LParen TT.RParen | TT.At TT.LBrace TT.RBrace | TT.LBrack TT.RBrack | TT.IncDec | &(TParams ~(TT.ContextualKeyword|TT.Id)) ((TT.LT|TT.Not) | TT.Dot TT.LBrack) => TParams | BracedBlock )* for (;;) { switch (LA0) { case TT.Dot: { if (Try_PrimaryExpr_Test0(0)) { la1 = LA(1); if (PrimaryExpr_set0.Contains((int) la1)) goto match1; else TParams(ref e); } else goto match1; } break; case TT.ColonColon: case TT.PtrArrow: case TT.QuickBind: goto match1; case TT.LParen: { if (Down(0) && Up(LA0 == TT.@as || LA0 == TT.@using || LA0 == TT.PtrArrow)) e = PrimaryExpr_NewStyleCast(e); else { var lp = MatchAny(); var rp = Match((int) TT.RParen); #line 510 "EcsParserGrammar.les" e = F.Call(e, ExprListInside(lp), e.Range.StartIndex, rp.EndIndex); #line default } } break; case TT.At: { Skip(); var lb = Match((int) TT.LBrace); var rb = Match((int) TT.RBrace); #line 512 "EcsParserGrammar.les" var stmts = StmtListInside(lb).ToRVList(); e = SetBaseStyle(F.Call(e, stmts, e.Range.StartIndex, rb.EndIndex), NodeStyle.Statement); #line default } break; case TT.LBrack: { var lb = MatchAny(); var rb = Match((int) TT.RBrack); var list = new RWList<LNode> { e }; e = F.Call(S.Bracks, AppendExprsInside(lb, list).ToRVList(), e.Range.StartIndex, rb.EndIndex); } break; case TT.IncDec: { var t = MatchAny(); #line 518 "EcsParserGrammar.les" e = F.Call(t.Value == S.PreInc ? S.PostInc : S.PostDec, e, e.Range.StartIndex, t.EndIndex); #line default } break; case TT.LT: { if (Try_PrimaryExpr_Test0(0)) TParams(ref e); else goto stop; } break; case TT.Not: TParams(ref e); break; case TT.LBrace: { var bb = BracedBlock(); #line 522 "EcsParserGrammar.les" if ((!e.IsCall || e.BaseStyle == NodeStyle.Operator)) e = F.Call(e, bb, e.Range.StartIndex, bb.Range.EndIndex); else e = e.WithArgs(e.Args.Add(bb)).WithRange(e.Range.StartIndex, bb.Range.EndIndex); #line default } break; default: goto stop; } continue; match1: { var op = MatchAny(); var rhs = Atom(); #line 507 "EcsParserGrammar.les" e = F.Call((Symbol) op.Value, e, rhs, e.Range.StartIndex, rhs.Range.EndIndex); #line default } } stop:; #line 528 "EcsParserGrammar.les" return e; #line default }
// 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; }
// GENERATED CODE EXAMPLE: The methods in this region generate // the for(;;) loop in this example and everything inside it, except // the calls to Match() which are generated by Visit(TerminalPred). // The generated code uses "goto" and "match" blocks in some cases // to avoid code duplication. This occurs when the matching code // requires multiple statements AND appears more than once in the // prediction tree. Otherwise, matching is done "inline" during // prediction. We generate a for(;;) loop for (...)*, and in certain // cases, we generates a do...while(false) loop for (...)?. // // rule Foo ==> @[ (('a'|'A') 'A')* 'a'..'z' 'a'..'z' ]; // public void Foo() // { // int la0, la1; // for (;;) { // la0 = LA(0); // if (la0 == 'a') { // la1 = LA(1); // if (la1 == 'A') // goto match1; // else // break; // } else if (la0 == 'A') // goto match1; // else // break; // match1: // { // Match('A', 'a'); // Match('A'); // } // } // MatchRange('a', 'z'); // MatchRange('a', 'z'); // } private void GenerateCodeForAlts(Alts alts, Dictionary <int, int> timesUsed, PredictionTree tree) { bool needError = LLPG.NeedsErrorBranch(tree, alts); if (!needError && alts.ErrorBranch != null) { LLPG.Output(Warning, alts, "The error branch will not be used because the other alternatives are exhaustive (cover all cases)"); } bool userDefinedError = needError && alts.ErrorBranch != null && alts.ErrorBranch != DefaultErrorBranch.Value; // Generate matching code for each arm. the "string" in each pair // becomes non-null if the matching code for that branch needs to be // split out (separated) from the prediction tree because it appears // multiple times in the tree. The string is the goto-label name. Pair <LNode, string>[] matchingCode = new Pair <LNode, string> [alts.Arms.Count + (userDefinedError ? 1: 0)]; MSet <int> unreachable = new MSet <int>(); int separateCount = 0; for (int i = 0; i < alts.Arms.Count; i++) { if (!timesUsed.ContainsKey(i)) { unreachable.Add(i); continue; } var codeForThisArm = new RWList <LNode>(); VisitWithNewTarget(alts.Arms[i], codeForThisArm); matchingCode[i].A = F.Braces(codeForThisArm.ToRVList()); if (timesUsed[i] > 1 && !SimpleEnoughToRepeat(matchingCode[i].A)) { separateCount++; matchingCode[i].B = alts.Arms[i].ChooseGotoLabel() ?? "match" + (i + 1).ToString(); } } // Add matching code for the error branch, if present. Note: the // default error branch, which is produced by IPGCodeGenHelper. // ErrorBranch() is handled differently: default error code can // differ at each error point in the prediction tree. Therefore // we generate it later, on-demand. if (userDefinedError) { int i = alts.Arms.Count; var errorHandler = new RWList <LNode>(); VisitWithNewTarget(alts.ErrorBranch, errorHandler); matchingCode[i].A = F.Braces(errorHandler.ToRVList()); if (timesUsed[ErrorAlt] > 1 && !SimpleEnoughToRepeat(matchingCode[i].A)) { matchingCode[i].B = "error"; separateCount++; } } // Print unreachability warnings if (unreachable.Count == 1) { LLPG.Output(Warning, alts, string.Format("Branch {{{0}}} is unreachable.", alts.AltName(unreachable.First()))); } else if (unreachable.Count > 1) { LLPG.Output(Warning, alts, string.Format("Branches {{{0}}} are unreachable.", unreachable.Select(i => alts.AltName(i)).Join(", "))); } if (!timesUsed.ContainsKey(ExitAlt) && alts.Mode != LoopMode.None) { LLPG.Output(Warning, alts, "Infinite loop. The exit branch is unreachable."); } Symbol loopType = null; // Choose a loop type for (...)* or (...)?: if (alts.Mode == LoopMode.Star) { loopType = S.For; } else if (alts.Mode == LoopMode.Opt) { if (alts.HasErrorBranch(LLPG) || alts.NonExitDefaultArmRequested()) { loopType = S.DoWhile; } } // If the code for an arm is nontrivial and appears multiple times // in the prediction table, it will have to be split out into a // labeled block and reached via "goto". I'd rather just do a goto // from inside one "if" statement to inside another, but in C# // (unlike in CIL, and unlike in C) that is prohibited :( DeduplicateLabels(matchingCode); var extraMatching = GenerateExtraMatchingCode(matchingCode, separateCount, ref loopType); if (separateCount != 0) { loopType = loopType ?? S.DoWhile; } Symbol breakMode = loopType; // used to request a "goto" label in addition to the loop LNode code = GeneratePredictionTreeCode(tree, matchingCode, ref breakMode); // Add break/continue between prediction tree and extra matching code, // if necessary. if (extraMatching.Count != 0 && CodeGenHelperBase.EndMayBeReachable(code)) { loopType = loopType ?? S.DoWhile; extraMatching.Insert(0, GetContinueStmt(loopType)); } if (!extraMatching.IsEmpty) { code = LNode.MergeLists(code, F.Braces(extraMatching), S.Braces); } if (loopType == S.For) { // (...)* => for (;;) {} code = F.Call(S.For, F._Missing, F._Missing, F._Missing, code); } else if (loopType == S.DoWhile) { // (...)? becomes "do {...} while(false);" IF the exit branch is NOT the default. // If the exit branch is the default, then no loop and no "break" is needed. code = F.Call(S.DoWhile, code, F.@false); } if (breakMode != loopType && breakMode != null) { // Add "stop:" label (plus extra ";" for C# compatibility, in // case the label ends the block in which it is located.) var stopLabel = F.Call(S.Label, F.Id(breakMode)) .PlusAttr(F.Trivia(S.TriviaRawTextAfter, ";")); code = LNode.MergeLists(code, stopLabel, S.Braces); } int oldCount = _target.Count; _target.SpliceAdd(code, S.Braces); // Add comment before code if (LLPG.AddComments) { var pos = alts.Basis.Range.Start; var comment = F.Trivia(S.TriviaSLCommentBefore, string.Format(" Line {0}: {1}", pos.Line, alts.ToString())); if (_target.Count > oldCount) { _target[oldCount] = _target[oldCount].PlusAttr(comment); } } }
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; }
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 }
LNode ArgList(Token lp, Token rp) { var list = new RWList<LNode>(); if ((Down(lp.Children))) { ArgList(list); Up(); } return F.List(list.ToRVList(), lp.StartIndex, rp.EndIndex); }
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 }
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 }
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(); }
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); }
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(); }
LNode PrimaryExpr() { var e = Atom(); // Line 518: greedy( (TT.ColonColon|TT.Dot|TT.PtrArrow|TT.QuickBind) Atom / PrimaryExpr_NewStyleCast / TT.LParen TT.RParen | TT.LBrack TT.RBrack | TT.IncDec | &(TParams ~(TT.ContextualKeyword|TT.Id)) ((TT.LT|TT.Not) | TT.Dot TT.LBrack) => TParams | BracedBlock )* for (;;) { switch (LA0) { case TT.Dot: { if (Try_PrimaryExpr_Test0(0)) { switch (LA(1)) { case TT.@base: case TT.@default: case TT.@this: case TT.@checked: case TT.@delegate: case TT.@new: case TT.@operator: case TT.@sizeof: case TT.@typeof: case TT.@unchecked: case TT.At: case TT.ContextualKeyword: case TT.Dot: case TT.Id: case TT.LBrace: case TT.Literal: case TT.LParen: case TT.Substitute: case TT.TypeKeyword: goto match1; default: TParams(ref e); break; } } else goto match1; } break; case TT.ColonColon: case TT.PtrArrow: case TT.QuickBind: goto match1; case TT.LParen: { if (Down(0) && Up(LA0 == TT.@as || LA0 == TT.@using || LA0 == TT.PtrArrow)) e = PrimaryExpr_NewStyleCast(e); else { var lp = MatchAny(); var rp = Match((int) TT.RParen); #line 522 "EcsParserGrammar.les" e = F.Call(e, ExprListInside(lp), e.Range.StartIndex, rp.EndIndex); #line default } } break; case TT.LBrack: { var lb = MatchAny(); var rb = Match((int) TT.RBrack); var list = new RWList<LNode> { e }; e = F.Call(S.IndexBracks, AppendExprsInside(lb, list).ToRVList(), e.Range.StartIndex, rb.EndIndex); } break; case TT.IncDec: { var t = MatchAny(); #line 526 "EcsParserGrammar.les" e = F.Call(t.Value == S.PreInc ? S.PostInc : S.PostDec, e, e.Range.StartIndex, t.EndIndex); #line default } break; case TT.LT: { if (Try_PrimaryExpr_Test0(0)) TParams(ref e); else goto stop; } break; case TT.Not: TParams(ref e); break; case TT.LBrace: { var bb = BracedBlock(); #line 530 "EcsParserGrammar.les" if ((!e.IsCall || e.BaseStyle == NodeStyle.Operator)) { e = F.Call(e, bb, e.Range.StartIndex, bb.Range.EndIndex); } else { e = e.WithArgs(e.Args.Add(bb)).WithRange(e.Range.StartIndex, bb.Range.EndIndex); } #line default } break; default: goto stop; } continue; match1: { var op = MatchAny(); var rhs = Atom(); #line 519 "EcsParserGrammar.les" e = F.Call((Symbol) op.Value, e, rhs, e.Range.StartIndex, rhs.Range.EndIndex); #line default } } stop:; #line 537 "EcsParserGrammar.les" return e; #line default }
public GenerateCodeVisitor(LLParserGenerator llpg) { LLPG = llpg; F = new LNodeFactory(llpg._sourceFile); _classBody = llpg._classBody; }
public virtual void Begin(RWList<LNode> classBody, ISourceFile sourceFile) { _classBody = classBody; F = new LNodeFactory(sourceFile); _setDeclNames = new Dictionary<IPGTerminalSet, Symbol>(); }
void NormalAttributes(ref RWList<LNode> attrs) { TokenType la0, la1; // Line 804: (&!{Down($LI) && Up(Try_Scan_AsmOrModLabel(0))} TT.LBrack TT.RBrack)* for (;;) { la0 = LA0; if (la0 == TT.LBrack) { if (!(Down(0) && Up(Try_Scan_AsmOrModLabel(0)))) { la1 = LA(1); if (la1 == TT.RBrack) { var t = MatchAny(); Skip(); #line 807 "EcsParserGrammar.les" if ((Down(t))) { AttributeContents(ref attrs); Up(); } #line default } else break; } else break; } else break; } }
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())); }
void AttributeContents(ref RWList<LNode> attrs) { TokenType la0, la1; #line 815 "EcsParserGrammar.les" Token attrTarget = default(Token); #line default // Line 817: greedy((@`.`(TT, noMacro(@return))|TT.ContextualKeyword|TT.Id) TT.Colon)? la0 = LA0; if (la0 == TT.@return || la0 == TT.ContextualKeyword || la0 == TT.Id) { la1 = LA(1); if (la1 == TT.Colon) { attrTarget = MatchAny(); Skip(); } } ExprList(attrs = attrs ?? new RWList<LNode>(), allowTrailingComma: true, allowUnassignedVarDecl: true); #line 822 "EcsParserGrammar.les" if (attrTarget.Value != null) { var attrTargetNode = IdNode(attrTarget); for (int i = 0; i < attrs.Count; i++) { var attr = attrs[i]; if ((!IsNamedArg(attr))) { attrs[i] = SetOperatorStyle(F.Call(S.NamedArg, attrTargetNode, attr, attrTarget.StartIndex, attr.Range.EndIndex)); } else { attrTargetNode = attrs[i].Args[1]; Error(attrTargetNode, "Syntax error: only one attribute target is allowed"); } } } #line default }
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; } }
void TParamAttributeKeywords(ref RWList<LNode> attrs) { TokenType la0; // Line 847: ((TT.@in|TT.AttrKeyword))* for (;;) { la0 = LA0; if (la0 == TT.@in || la0 == TT.AttrKeyword) { var t = MatchAny(); #line 848 "EcsParserGrammar.les" (attrs = attrs ?? new RWList<LNode>()).Add(IdNode(t)); #line default } else break; } }
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 }
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; }