public void Run(AstNode node) { Run(node, null); // Declare all the variables at the end, after all the logic has run. // This is done so that definite assignment analysis can work on a single representation and doesn't have to be updated // when we change the AST. foreach (var v in variablesToDeclare) { if (v.ReplacedAssignment == null) { BlockStatement block = (BlockStatement)v.InsertionPoint.Parent; block.Statements.InsertBefore( v.InsertionPoint, new VariableDeclarationStatement((AstType)v.Type.Clone(), v.Name)); } } // First do all the insertions, then do all the replacements. This is necessary because a replacement might remove our reference point from the AST. foreach (var v in variablesToDeclare) { if (v.ReplacedAssignment != null) { // We clone the right expression so that it doesn't get removed from the old ExpressionStatement, // which might be still in use by the definite assignment graph. VariableDeclarationStatement varDecl = new VariableDeclarationStatement { Type = (AstType)v.Type.Clone(), Variables = { new VariableInitializer(v.Name, v.ReplacedAssignment.Right.Detach()).CopyAnnotationsFrom(v.ReplacedAssignment) } }; ExpressionStatement es = v.ReplacedAssignment.Parent as ExpressionStatement; if (es != null) { // Note: if this crashes with 'Cannot replace the root node', check whether two variables were assigned the same name es.ReplaceWith(varDecl.CopyAnnotationsFrom(es)); } else { v.ReplacedAssignment.ReplaceWith(varDecl); } } } variablesToDeclare = null; }
public void Run(AstNode node) { Run(node, null); // Declare all the variables at the end, after all the logic has run. // This is done so that definite assignment analysis can work on a single representation and doesn't have to be updated // when we change the AST. foreach (var v in variablesToDeclare) { if (v.ReplacedAssignment == null) { BlockStatement block = (BlockStatement)v.InsertionPoint.Parent; var decl = new VariableDeclarationStatement(v.ILVariable != null && v.ILVariable.IsParameter ? TextTokenKind.Parameter : TextTokenKind.Local, (AstType)v.Type.Clone(), v.Name); if (v.ILVariable != null) { decl.Variables.Single().AddAnnotation(v.ILVariable); } block.Statements.InsertBefore( v.InsertionPoint, decl); } } // First do all the insertions, then do all the replacements. This is necessary because a replacement might remove our reference point from the AST. foreach (var v in variablesToDeclare) { if (v.ReplacedAssignment != null) { // We clone the right expression so that it doesn't get removed from the old ExpressionStatement, // which might be still in use by the definite assignment graph. VariableInitializer initializer = new VariableInitializer(v.ILVariable != null && v.ILVariable.IsParameter ? TextTokenKind.Parameter : TextTokenKind.Local, v.Name, v.ReplacedAssignment.Right.Detach()).CopyAnnotationsFrom(v.ReplacedAssignment).WithAnnotation(v.ILVariable); VariableDeclarationStatement varDecl = new VariableDeclarationStatement { Type = (AstType)v.Type.Clone(), Variables = { initializer } }; ExpressionStatement es = v.ReplacedAssignment.Parent as ExpressionStatement; if (es != null) { // Note: if this crashes with 'Cannot replace the root node', check whether two variables were assigned the same name es.ReplaceWith(varDecl.CopyAnnotationsFrom(es)); varDecl.AddAnnotation(es.GetAllRecursiveILRanges()); } else { varDecl.AddAnnotation(v.ReplacedAssignment.GetAllRecursiveILRanges()); v.ReplacedAssignment.ReplaceWith(varDecl); } } } variablesToDeclare.Clear(); }
/// <summary> /// Declares a variable in the smallest required scope. /// </summary> /// <param name="node">The root of the subtree being searched for the best insertion position</param> /// <param name="type">The type of the new variable</param> /// <param name="name">The name of the new variable</param> /// <param name="allowPassIntoLoops">Whether the variable is allowed to be placed inside a loop</param> public static VariableDeclarationStatement DeclareVariable(AstNode node, AstType type, string name, bool allowPassIntoLoops = true) { VariableDeclarationStatement result = null; AstNode pos = FindInsertPos(node, name, allowPassIntoLoops); if (pos != null) { Match m = assignmentPattern.Match(pos); if (m != null && m.Get<IdentifierExpression>("ident").Single().Identifier == name) { result = new VariableDeclarationStatement(type, name, m.Get<Expression>("init").Single().Detach()); result.Variables.Single().CopyAnnotationsFrom(((ExpressionStatement)pos).Expression); result.CopyAnnotationsFrom(pos); pos.ReplaceWith(result); } else { result = new VariableDeclarationStatement(type, name); pos.Parent.InsertChildBefore(pos, result, BlockStatement.StatementRole); } } return result; }
public void Run(AstNode node) { Run(node, null); // Declare all the variables at the end, after all the logic has run. // This is done so that definite assignment analysis can work on a single representation and doesn't have to be updated // when we change the AST. foreach (var v in variablesToDeclare) { if (v.ReplacedAssignment == null) { BlockStatement block = (BlockStatement)v.InsertionPoint.Parent; block.Statements.InsertBefore( v.InsertionPoint, new VariableDeclarationStatement((AstType)v.Type.Clone(), v.Name)); } } // First do all the insertions, then do all the replacements. This is necessary because a replacement might remove our reference point from the AST. foreach (var v in variablesToDeclare) { if (v.ReplacedAssignment != null) { // We clone the right expression so that it doesn't get removed from the old ExpressionStatement, // which might be still in use by the definite assignment graph. VariableDeclarationStatement varDecl = new VariableDeclarationStatement { Type = (AstType)v.Type.Clone(), Variables = { new VariableInitializer(v.Name, v.ReplacedAssignment.Right.Detach()).CopyAnnotationsFrom(v.ReplacedAssignment) } }; ExpressionStatement es = v.ReplacedAssignment.Parent as ExpressionStatement; if (es != null) { es.ReplaceWith(varDecl.CopyAnnotationsFrom(es)); } else { v.ReplacedAssignment.ReplaceWith(varDecl); } } } variablesToDeclare = null; }