Browse Source

Support #regions in JavaScript code.

pull/18/head
Matt Ward 14 years ago
parent
commit
3b93ba0fb6
  1. 4
      src/AddIns/BackendBindings/JavaScriptBinding/Project/JavaScriptBinding.csproj
  2. 6
      src/AddIns/BackendBindings/JavaScriptBinding/Project/Src/ITokenExtensions.cs
  3. 6
      src/AddIns/BackendBindings/JavaScriptBinding/Project/Src/JavaScriptAst.cs
  4. 7
      src/AddIns/BackendBindings/JavaScriptBinding/Project/Src/JavaScriptAstWalker.cs
  5. 42
      src/AddIns/BackendBindings/JavaScriptBinding/Project/Src/JavaScriptRegion.cs
  6. 34
      src/AddIns/BackendBindings/JavaScriptBinding/Project/Src/JavaScriptRegionEnd.cs
  7. 51
      src/AddIns/BackendBindings/JavaScriptBinding/Project/Src/JavaScriptRegionStart.cs
  8. 64
      src/AddIns/BackendBindings/JavaScriptBinding/Project/Src/JavaScriptRegionWalker.cs
  9. 224
      src/AddIns/BackendBindings/JavaScriptBinding/Test/Src/JavaScriptParserTests.cs

4
src/AddIns/BackendBindings/JavaScriptBinding/Project/JavaScriptBinding.csproj

@ -57,11 +57,15 @@ @@ -57,11 +57,15 @@
<Compile Include="Src\JavaScriptAst.cs" />
<Compile Include="Src\JavaScriptAstFactory.cs" />
<Compile Include="Src\JavaScriptAstWalker.cs" />
<Compile Include="Src\JavaScriptRegion.cs" />
<Compile Include="Src\JavaScriptRegionEnd.cs" />
<Compile Include="Src\JavaScriptRegionStart.cs" />
<Compile Include="Src\JavaScriptCompilationUnit.cs" />
<Compile Include="Src\JavaScriptFunctionDefinition.cs" />
<Compile Include="Src\JavaScriptGlobalClass.cs" />
<Compile Include="Src\JavaScriptMethodRegion.cs" />
<Compile Include="Src\JavaScriptParser.cs" />
<Compile Include="Src\JavaScriptRegionWalker.cs" />
</ItemGroup>
<ItemGroup>
<Folder Include="Src" />

6
src/AddIns/BackendBindings/JavaScriptBinding/Project/Src/ITokenExtensions.cs

@ -3,6 +3,7 @@ @@ -3,6 +3,7 @@
using System;
using Antlr.Runtime;
using Xebic.Parsers.ES3;
namespace ICSharpCode.JavaScriptBinding
{
@ -17,5 +18,10 @@ namespace ICSharpCode.JavaScriptBinding @@ -17,5 +18,10 @@ namespace ICSharpCode.JavaScriptBinding
{
return token.CharPositionInLine + token.Text.Length + 1;
}
public static bool IsSingleLineComment(this IToken token)
{
return token.Type == ES3Lexer.SingleLineComment;
}
}
}

6
src/AddIns/BackendBindings/JavaScriptBinding/Project/Src/JavaScriptAst.cs

@ -2,6 +2,7 @@ @@ -2,6 +2,7 @@
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
using System;
using System.Collections.Generic;
using Antlr.Runtime;
using Antlr.Runtime.Tree;
@ -30,5 +31,10 @@ namespace ICSharpCode.JavaScriptBinding @@ -30,5 +31,10 @@ namespace ICSharpCode.JavaScriptBinding
{
return tokenStream.Get(index);
}
public IList<IToken> GetTokens()
{
return tokenStream.GetTokens();
}
}
}

7
src/AddIns/BackendBindings/JavaScriptBinding/Project/Src/JavaScriptAstWalker.cs

@ -26,6 +26,7 @@ namespace ICSharpCode.JavaScriptBinding @@ -26,6 +26,7 @@ namespace ICSharpCode.JavaScriptBinding
{
if (ast.IsValid) {
Walk(ast.Tree);
WalkRegions();
}
}
@ -52,5 +53,11 @@ namespace ICSharpCode.JavaScriptBinding @@ -52,5 +53,11 @@ namespace ICSharpCode.JavaScriptBinding
Walk(child);
}
}
void WalkRegions()
{
var regionWalker = new JavaScriptRegionWalker(ast, compilationUnit);
regionWalker.Walk();
}
}
}

42
src/AddIns/BackendBindings/JavaScriptBinding/Project/Src/JavaScriptRegion.cs

@ -0,0 +1,42 @@ @@ -0,0 +1,42 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
using System;
using System.Collections.Generic;
using ICSharpCode.SharpDevelop.Dom;
namespace ICSharpCode.JavaScriptBinding
{
public class JavaScriptRegion
{
JavaScriptRegionStart start;
JavaScriptRegionEnd end;
public JavaScriptRegion(JavaScriptRegionStart start, JavaScriptRegionEnd end)
{
this.start = start;
this.end = end;
}
public void AddRegion(IList<FoldingRegion> foldingRegions)
{
FoldingRegion namedFoldingRegion = CreateFoldingRegion();
foldingRegions.Add(namedFoldingRegion);
}
FoldingRegion CreateFoldingRegion()
{
DomRegion location = GetRegionLocation();
return new FoldingRegion(start.Name, location);
}
DomRegion GetRegionLocation()
{
int beginLine = start.Line;
int endLine = end.Line;
int beginColumn = start.StartColumn;
int endColumn = end.EndColumn;
return new DomRegion(beginLine, beginColumn, endLine, endColumn);
}
}
}

34
src/AddIns/BackendBindings/JavaScriptBinding/Project/Src/JavaScriptRegionEnd.cs

@ -0,0 +1,34 @@ @@ -0,0 +1,34 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
using System;
using Antlr.Runtime;
namespace ICSharpCode.JavaScriptBinding
{
public class JavaScriptRegionEnd
{
public static readonly string RegionEndText = "//#endregion";
public static readonly int RegionEndTextLength = RegionEndText.Length;
IToken token;
public JavaScriptRegionEnd(IToken token)
{
this.token = token;
}
public static bool IsRegionEnd(IToken token)
{
return token.Text.StartsWith(RegionEndText);
}
public int Line {
get { return token.Line; }
}
public int EndColumn {
get { return token.BeginColumn() + RegionEndTextLength; }
}
}
}

51
src/AddIns/BackendBindings/JavaScriptBinding/Project/Src/JavaScriptRegionStart.cs

@ -0,0 +1,51 @@ @@ -0,0 +1,51 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
using System;
using Antlr.Runtime;
namespace ICSharpCode.JavaScriptBinding
{
public class JavaScriptRegionStart
{
public static readonly string RegionStartText = "//#region ";
public static readonly int RegionStartTextLength = RegionStartText.Length;
IToken token;
string name;
public JavaScriptRegionStart(IToken token)
{
this.token = token;
}
public string Name {
get {
if (name == null) {
GetName();
}
return name;
}
}
void GetName()
{
string text = token.Text;
int index = text.IndexOf(RegionStartText);
name = text.Substring(index + RegionStartTextLength);
}
public static bool IsRegionStart(IToken token)
{
return token.Text.StartsWith(RegionStartText);
}
public int Line {
get { return token.Line; }
}
public int StartColumn {
get { return token.BeginColumn(); }
}
}
}

64
src/AddIns/BackendBindings/JavaScriptBinding/Project/Src/JavaScriptRegionWalker.cs

@ -0,0 +1,64 @@ @@ -0,0 +1,64 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
using System;
using System.Collections.Generic;
using Antlr.Runtime;
using Antlr.Runtime.Tree;
using ICSharpCode.SharpDevelop.Dom;
using Xebic.Parsers.ES3;
namespace ICSharpCode.JavaScriptBinding
{
public class JavaScriptRegionWalker
{
JavaScriptAst ast;
ICompilationUnit compilationUnit;
Stack<JavaScriptRegionStart> regions;
public JavaScriptRegionWalker(
JavaScriptAst ast,
ICompilationUnit compilationUnit)
{
this.ast = ast;
this.compilationUnit = compilationUnit;
}
public void Walk()
{
regions = new Stack<JavaScriptRegionStart>();
foreach (IToken token in ast.GetTokens()) {
if (token.IsSingleLineComment()) {
WalkComment(token);
}
}
}
void WalkComment(IToken token)
{
if (JavaScriptRegionStart.IsRegionStart(token)) {
WalkRegionStart(token);
} else if (JavaScriptRegionEnd.IsRegionEnd(token)) {
WalkRegionEnd(token);
}
}
void WalkRegionStart(IToken token)
{
var regionStart = new JavaScriptRegionStart(token);
regions.Push(regionStart);
}
void WalkRegionEnd(IToken token)
{
if (regions.Count > 0) {
JavaScriptRegionStart regionStart = regions.Pop();
var regionEnd = new JavaScriptRegionEnd(token);
var region = new JavaScriptRegion(regionStart, regionEnd);
region.AddRegion(compilationUnit.FoldingRegions);
}
}
}
}

224
src/AddIns/BackendBindings/JavaScriptBinding/Test/Src/JavaScriptParserTests.cs

@ -66,6 +66,14 @@ namespace JavaScriptBinding.Tests @@ -66,6 +66,14 @@ namespace JavaScriptBinding.Tests
get { return FirstClass.Methods[0]; }
}
FoldingRegion FirstRegion {
get { return compilationUnit.FoldingRegions[0]; }
}
FoldingRegion SecondRegion {
get { return compilationUnit.FoldingRegions[1]; }
}
[Test]
public void CanParse_CSharpProjectPassed_ReturnsTrue()
{
@ -279,5 +287,221 @@ namespace JavaScriptBinding.Tests @@ -279,5 +287,221 @@ namespace JavaScriptBinding.Tests
Assert.AreEqual(expectedRegion, methodBodyRegion);
}
[Test]
public void Parse_JavaScriptCodeHasOneRegion_OneFoldingRegionAddedToCompilationUnit()
{
string code =
"//#region MyRegion\r\n" +
"var a = 1;\r\n" +
"//#endregion\r\n";
ParseJavaScript(code);
int count = compilationUnit.FoldingRegions.Count;
Assert.AreEqual(1, count);
}
[Test]
public void Parse_JavaScriptCodeHasOneRegionWithName_FoldingRegionAddedWithName()
{
string code =
"//#region MyRegion\r\n" +
"var a = 1;\r\n" +
"//#endregion\r\n";
ParseJavaScript(code);
string name = FirstRegion.Name;
Assert.AreEqual("MyRegion", name);
}
[Test]
public void Parse_JavaScriptCodeHasNoRegions_NoFoldingRegionsAddedToCompilationUnit()
{
string code = "var a = 1;";
ParseJavaScript(code);
int count = compilationUnit.FoldingRegions.Count;
Assert.AreEqual(0, count);
}
[Test]
public void Parse_JavaScriptCodeSingleCommentEndsWithRegionTextButDoesNotStartWithRegion_NoRegionsAddedToCompilationUnit()
{
string code =
"//not a #region test\r\n" +
"var a = 1;\r\n" +
"//not an #endregion\r\n";
ParseJavaScript(code);
Assert.AreEqual(0, compilationUnit.FoldingRegions.Count);
}
[Test]
public void Parse_JavaScriptCodeHasOneRegion_RegionLocationIsSpecified()
{
string code =
"//#region MyRegion\r\n" +
"var a = 1;\r\n" +
"//#endregion\r\n";
ParseJavaScript(code);
DomRegion location = FirstRegion.Region;
int beginLine = 1;
int endLine = 3;
int beginColumn = 1;
int endColumn = 13;
var expectedLocation = new DomRegion(beginLine, beginColumn, endLine, endColumn);
Assert.AreEqual(expectedLocation, location);
}
[Test]
public void Parse_JavaScriptCodeHasRegionStartOnly_NoRegionsAddedToCompilationUnit()
{
string code =
"//#region MyRegion\r\n" +
"var a = 1;\r\n";
ParseJavaScript(code);
Assert.AreEqual(0, compilationUnit.FoldingRegions.Count);
}
[Test]
public void Parse_JavaScriptCodeHasOneRegionWithEndRegionFollowedByText_TextFollowingEndRegionIsNotPartOfFold()
{
string code =
"//#region MyRegion\r\n" +
"var a = 1;\r\n" +
"//#endregion abc\r\n";
ParseJavaScript(code);
DomRegion location = FirstRegion.Region;
int beginLine = 1;
int endLine = 3;
int beginColumn = 1;
int endColumn = 13;
var expectedLocation = new DomRegion(beginLine, beginColumn, endLine, endColumn);
Assert.AreEqual(expectedLocation, location);
}
[Test]
public void Parse_JavaScriptCodeHasTwoRegions_TwoRegionsAddedToCompilationUnit()
{
string code =
"//#region One\r\n" +
"var a = 1;\r\n" +
"//#endregion\r\n" +
"\r\n" +
"//#region Two\r\n" +
"var b = 1;\r\n" +
"//#endregion\r\n";
ParseJavaScript(code);
Assert.AreEqual(2, compilationUnit.FoldingRegions.Count);
}
[Test]
public void Parse_JavaScriptCodeHasTwoRegions_RegionsHaveCorrectLocationsAndNames()
{
string code =
"//#region One\r\n" +
"var a = 1;\r\n" +
"//#endregion\r\n" +
"\r\n" +
"//#region Two\r\n" +
"var b = 1;\r\n" +
"//#endregion\r\n";
ParseJavaScript(code);
DomRegion firstRegionLocation = FirstRegion.Region;
int beginLine = 1;
int endLine = 3;
int beginColumn = 1;
int endColumn = 13;
var expectedFirstRegionLocation = new DomRegion(beginLine, beginColumn, endLine, endColumn);
DomRegion secondRegionLocation = SecondRegion.Region;
beginLine = 5;
endLine = 7;
beginColumn = 1;
endColumn = 13;
var expectedSecondRegionLocation = new DomRegion(beginLine, beginColumn, endLine, endColumn);
Assert.AreEqual(expectedFirstRegionLocation, firstRegionLocation);
Assert.AreEqual("One", FirstRegion.Name);
Assert.AreEqual(expectedSecondRegionLocation, secondRegionLocation);
Assert.AreEqual("Two", SecondRegion.Name);
}
[Test]
public void Parse_JavaScriptCodeHasEndRegionButNoStartRegion_NoRegionsAddedToCompilationUnit()
{
string code =
"var a = 1;\r\n" +
"//#endregion\r\n";
ParseJavaScript(code);
Assert.AreEqual(0, compilationUnit.FoldingRegions.Count);
}
[Test]
public void Parse_JavaScriptCodeHasTwoNestedRegions_RegionsHaveCorrectLocationsAndNames()
{
string code =
"//#region One\r\n" +
"var a = 1;\r\n" +
"//#region Two\r\n" +
"var b = 1;\r\n" +
"//#endregion\r\n" +
"var c = 1;\r\n" +
"//#endregion\r\n";
ParseJavaScript(code);
DomRegion firstRegionLocation = FirstRegion.Region;
int beginLine = 3;
int endLine = 5;
int beginColumn = 1;
int endColumn = 13;
var expectedFirstRegionLocation = new DomRegion(beginLine, beginColumn, endLine, endColumn);
DomRegion secondRegionLocation = SecondRegion.Region;
beginLine = 1;
endLine = 7;
beginColumn = 1;
endColumn = 13;
var expectedSecondRegionLocation = new DomRegion(beginLine, beginColumn, endLine, endColumn);
Assert.AreEqual(expectedFirstRegionLocation, firstRegionLocation);
Assert.AreEqual("Two", FirstRegion.Name);
Assert.AreEqual(expectedSecondRegionLocation, secondRegionLocation);
Assert.AreEqual("One", SecondRegion.Name);
}
}
}

Loading…
Cancel
Save