Paradox Game Engine  v1.0.0 beta06
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Events Macros Pages
BreakContinueVisitor.cs
Go to the documentation of this file.
1 // Copyright (c) 2014 Silicon Studio Corp. (http://siliconstudio.co.jp)
2 // This file is distributed under GPL v3. See LICENSE.md for details.
3 using System;
4 using System.Collections.Generic;
5 using System.Linq;
6 using System.Text;
7 using System.Threading.Tasks;
8 
9 using SiliconStudio.Shaders.Ast;
10 using SiliconStudio.Shaders.Parser;
11 using SiliconStudio.Shaders.Visitor;
12 
13 namespace SiliconStudio.Shaders.Convertor
14 {
15  internal class BreakContinueVisitor : ShaderVisitor
16  {
17  /// <summary>
18  /// the logger
19  /// </summary>
20  private ParsingResult parserResult;
21 
22  /// <summary>
23  /// the keyword to look after
24  /// </summary>
25  private string keyword;
26 
27  /// <summary>
28  /// list of the "scopes" ie. where a break/continue test has to be performed
29  /// </summary>
30  private List<List<Statement>> scopeList = new List<List<Statement>>();
31 
32  /// <summary>
33  /// current stack of "scopes"
34  /// </summary>
35  private Stack<Statement> containerStack = new Stack<Statement>();
36 
37  public BreakContinueVisitor()
38  : base(false, true)
39  {
40  parserResult = new ParsingResult();
41  }
42 
43  public bool Run(ForStatement forStatement, Variable breakFlag, string keywordName, ParsingResult logger)
44  {
45  keyword = keywordName;
46 
47  Visit(forStatement.Body);
48 
49  if (logger != null)
50  parserResult.CopyTo(logger);
51 
52  if (parserResult.HasErrors)
53  return false;
54 
55  TransformBreaks(breakFlag);
56 
57  return scopeList.Count > 0;
58  }
59 
60  [Visit]
61  protected void Visit(KeywordExpression expression)
62  {
63  if (expression.Name.Text == keyword)
64  {
65  var list = new List<Statement>(containerStack);
66  list.Reverse();
67  if (ParentNode is ExpressionStatement)
68  list.Add(ParentNode as ExpressionStatement);
69  else
70  parserResult.Error("{0} keyword detected, but outside of an ExpressionStatement. It is impossible to unroll the loop", expression.Span, keyword);
71 
72  scopeList.Add(list);
73  }
74  }
75 
76  [Visit]
77  protected void Visit(BlockStatement blockStatement)
78  {
79  containerStack.Push(blockStatement);
80  Visit((Node)blockStatement);
81  containerStack.Pop();
82  }
83 
84  [Visit]
85  protected void Visit(WhileStatement whileStatement) { }
86 
87  [Visit]
88  protected void Visit(ForStatement forStatement) { }
89 
90  [Visit]
91  protected void Visit(StatementList statementList)
92  {
93  containerStack.Push(statementList);
94  Visit((Node)statementList);
95  containerStack.Pop();
96  }
97 
98  [Visit]
99  protected void Visit(IfStatement ifStatement)
100  {
101  containerStack.Push(ifStatement);
102  Visit((Node)ifStatement);
103  containerStack.Pop();
104  }
105 
106  /// <summary>
107  /// Inserts the break variable in the flow of the loop
108  /// </summary>
109  /// <param name="breakFlag">the break variable</param>
110  protected void TransformBreaks(Variable breakFlag)
111  {
112  var breakTest = new UnaryExpression(UnaryOperator.LogicalNot, new VariableReferenceExpression(breakFlag));
113  scopeList.Reverse();
114  foreach (var breakScope in scopeList)
115  {
116  for (int i = 0; i < breakScope.Count - 1; ++i)
117  {
118  var currentScope = breakScope[i];
119  var nextScope = breakScope[i+1];
120 
121  if (currentScope is StatementList)
122  {
123  var typedScope = currentScope as StatementList;
124  var index = typedScope.Statements.IndexOf(nextScope);
125  if (index == -1)
126  {
127  parserResult.Error("unable to find the next scope when replacing break/continue", nextScope.Span);
128  break;
129  }
130 
131  var testBlock = new IfStatement();
132  testBlock.Condition = breakTest;
133  var thenBlock = new StatementList();
134  for (int j = index + 1; j < typedScope.Statements.Count; ++j)
135  thenBlock.Add(typedScope.Statements[j]);
136  testBlock.Then = thenBlock;
137 
138  typedScope.Statements.RemoveRange(index + 1, typedScope.Statements.Count - index - 1);
139  if (typedScope.Statements.Count > 0 && i != breakScope.Count - 2) // do not add the statements behind the break/continue
140  typedScope.Statements.Add(testBlock);
141  }
142  }
143 
144  var last = breakScope.LastOrDefault() as ExpressionStatement;
145  if (last != null)
146  last.Expression = new AssignmentExpression(AssignmentOperator.Default, new VariableReferenceExpression(breakFlag), new LiteralExpression(true));
147  }
148  }
149  }
150 }
Statement Body
Gets or sets the body.
Definition: ForStatement.cs:76
UnaryOperator
Unary operator used in all binary expressions (except assignment expression).
Keyword expression statement like continue; break; discard;
string Text
Gets or sets the name.
Definition: Identifier.cs:77
While and Do-While statement.
AssignmentOperator
Assignment operator used in assignment expression (a = b) or statements (a = b;)
Abstract node.
Definition: Node.cs:15
A variable declaration.
Definition: Variable.cs:11
Identifier Name
Gets or sets the name.
document false