Skip to content

Commit 140295b

Browse files
author
Kapil Borle
committed
Add a class to handle token operations
1 parent 1fd4db9 commit 140295b

File tree

2 files changed

+100
-0
lines changed

2 files changed

+100
-0
lines changed

Engine/ScriptAnalyzerEngine.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,7 @@
101101
<DesignTime>True</DesignTime>
102102
<DependentUpon>Strings.resx</DependentUpon>
103103
</Compile>
104+
<Compile Include="TokenOperations.cs" />
104105
<Compile Include="VariableAnalysis.cs" />
105106
<Compile Include="VariableAnalysisBase.cs" />
106107
</ItemGroup>

Engine/TokenOperations.cs

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using System.Management.Automation.Language;
5+
6+
namespace Microsoft.Windows.PowerShell.ScriptAnalyzer
7+
{
8+
// TODO Move all token query related methods here
9+
/// <summary>
10+
/// A class to encapsulate all the token querying operations.
11+
/// </summary>
12+
public class TokenOperations
13+
{
14+
private readonly Token[] tokens;
15+
private readonly Ast ast;
16+
17+
/// <summary>
18+
/// Initializes the fields of the TokenOperations class.
19+
/// </summary>
20+
/// <param name="tokens">Tokens referring to the input AST.</param>
21+
/// <param name="ast">AST that needs to be analyzed.</param>
22+
public TokenOperations(Token[] tokens, Ast ast)
23+
{
24+
if (tokens == null)
25+
{
26+
throw new ArgumentNullException(nameof(tokens));
27+
}
28+
29+
if (ast == null)
30+
{
31+
throw new ArgumentNullException(nameof(ast));
32+
}
33+
34+
this.tokens = tokens;
35+
this.ast = ast;
36+
}
37+
38+
/// <summary>
39+
/// Return tokens of kind LCurly that begin a scriptblock expression in an command element.
40+
///
41+
/// E.g. Get-Process * | where { $_.Name -like "powershell" }
42+
/// In the above example it will return the open brace following the where command.
43+
/// </summary>
44+
/// <returns>An enumerable of type Token</returns>
45+
public IEnumerable<Token> GetOpenBracesInCommandElements()
46+
{
47+
return GetBraceInCommandElement(TokenKind.LCurly);
48+
}
49+
50+
51+
/// <summary>
52+
/// Return tokens of kind RCurly that end a scriptblock expression in an command element.
53+
///
54+
/// E.g. Get-Process * | where { $_.Name -like "powershell" }
55+
/// In the above example it will return the close brace following "powershell".
56+
/// </summary>
57+
/// <returns>An enumerable of type Token</returns>
58+
public IEnumerable<Token> GetCloseBraceInCommandElement()
59+
{
60+
return GetBraceInCommandElement(TokenKind.RCurly);
61+
}
62+
63+
private IEnumerable<Token> GetBraceInCommandElement(TokenKind tokenKind)
64+
{
65+
var cmdElemAsts = ast.FindAll(x => x is CommandElementAst && x is ScriptBlockExpressionAst, true);
66+
if (cmdElemAsts == null)
67+
{
68+
yield break;
69+
}
70+
71+
Func<Token, Ast, bool> predicate;
72+
73+
switch (tokenKind)
74+
{
75+
case TokenKind.LCurly:
76+
predicate = (x, cmdElemAst) =>
77+
x.Kind == TokenKind.LCurly && x.Extent.StartOffset == cmdElemAst.Extent.StartOffset;
78+
break;
79+
80+
case TokenKind.RCurly:
81+
predicate = (x, cmdElemAst) =>
82+
x.Kind == TokenKind.RCurly && x.Extent.EndOffset == cmdElemAst.Extent.EndOffset;
83+
break;
84+
85+
default:
86+
throw new ArgumentException("", nameof(tokenKind));
87+
}
88+
89+
foreach (var cmdElemAst in cmdElemAsts)
90+
{
91+
var tokenFound = tokens.FirstOrDefault(token => predicate(token, cmdElemAst));
92+
if (tokenFound != null)
93+
{
94+
yield return tokenFound;
95+
}
96+
}
97+
}
98+
}
99+
}

0 commit comments

Comments
 (0)