[scripting] support for preserving as many comments as possible

This commit is contained in:
Adriano Carlos Verona 2017-08-18 15:53:34 -03:00
Родитель d6efba9c15
Коммит d435c7666e
9 изменённых файлов: 836 добавлений и 89 удалений

Просмотреть файл

@ -719,13 +719,16 @@ namespace UnityScript2CSharp.Tests
yield return new TestCaseData($"{comment}\r\nfunction F() {{ }}", $"{comment}\r\npublic virtual void F() {{ }}").SetName("Above SingleLine");
// Multiline
comment = "/* C1 */ ";
comment = "/* C1 */";
yield return new TestCaseData($"function F() {{ return 42; {comment}\r\n}}", $"public virtual int F() {{ return 42 {comment}; }}").SetName("Right MultiLine");
yield return new TestCaseData($"{comment}\nfunction F() {{ }}", $"{comment}\npublic virtual void F() {{ }}").SetName("Above MultiLine");
yield return new TestCaseData($"{comment}\r\nfunction F() {{ }}", $"{comment}\r\npublic virtual void F() {{ }}").SetName("Above MultiLine");
yield return new TestCaseData($"function F() {{ var x = 42;\r\n{comment}\r\nreturn x; }}", $"public virtual int F() {{ int x = 42;\r\n{comment}\r\nreturn x; }}").SetName("Below MultiLine");
yield return new TestCaseData($"function F() : int {{ {comment} return 42; }}", $"public virtual int F() {{ {comment} return 42; }}").SetName("Left MultiLine");
yield return new TestCaseData("function F() : int { return 42 /*1*/; /*2*/ }", "public virtual int F() { return 42 /*1*/ /*2*/; }").SetName("Multiple multiLine comments");
yield return new TestCaseData("function F(/*B*/ i:int /*A*/ ) { }", "public virtual void F(/*B*/int /*A*/ i) { }").SetName("In Parameters");
yield return new TestCaseData("// 1\r\nprivate var i:int;\r\nfunction F() { }", "// 1\r\nprivate int i;\r\npublic virtual void F() { }").SetName("Above Fields");
}
private static IEnumerable CSharpNonClashingKeywords()

Просмотреть файл

@ -30,6 +30,10 @@ namespace UnityScript2CSharp
[Option('i', HelpText = "Ignore compilation errors. This allows the conversion process to continue instead of aborting.")] public bool IgnoreErrors { get; set; }
[Option(HelpText = "Do not try to preserve comments (Use this option if processing comments cause any issues).", DefaultValue = false)] public bool SkipComments { get; set; }
[Option(HelpText = "Show a list of comments that were not written to the converted sources (used to help identifying issues with the comment processing code).")] public bool ShowOrphanComments { get; set; }
[Option('n', "dry-run", HelpText = "Run the conversion but do not change/create any files on disk.")] public bool DryRun { get; set; }
[Option('v', "verbose", HelpText = "Show verbose messages.")] public bool Verbose { get; set; }

Просмотреть файл

@ -0,0 +1,556 @@
using System;
using System.Collections.Generic;
using Boo.Lang.Compiler.Ast;
using Attribute = Boo.Lang.Compiler.Ast.Attribute;
namespace UnityScript2CSharp
{
internal class OrphanCommentVisitor : DepthFirstVisitor
{
private void Check(Node node)
{
if (node.ContainsAnnotation("COMMENTS"))
{
var comments = (IList<Comment>) node["COMMENTS"];
foreach (var comment in comments)
{
Console.WriteLine($"[ORPHAN COMMENT | {node.NodeType}, {comment.AnchorKind}] {node.LexicalInfo} : {comment.Token.getText()}\r\n\t{node}");
}
}
}
public override void OnCompileUnit(CompileUnit node)
{
base.OnCompileUnit(node);
Check(node);
}
public override void OnTypeMemberStatement(TypeMemberStatement node)
{
base.OnTypeMemberStatement(node);
Check(node);
}
public override void OnExplicitMemberInfo(ExplicitMemberInfo node)
{
base.OnExplicitMemberInfo(node);
Check(node);
}
public override void OnSimpleTypeReference(SimpleTypeReference node)
{
base.OnSimpleTypeReference(node);
Check(node);
}
public override void OnArrayTypeReference(ArrayTypeReference node)
{
base.OnArrayTypeReference(node);
Check(node);
}
public override void OnCallableTypeReference(CallableTypeReference node)
{
base.OnCallableTypeReference(node);
Check(node);
}
public override void OnGenericTypeReference(GenericTypeReference node)
{
base.OnGenericTypeReference(node);
Check(node);
}
public override void OnGenericTypeDefinitionReference(GenericTypeDefinitionReference node)
{
base.OnGenericTypeDefinitionReference(node);
Check(node);
}
public override void OnCallableDefinition(CallableDefinition node)
{
base.OnCallableDefinition(node);
Check(node);
}
public override void OnNamespaceDeclaration(NamespaceDeclaration node)
{
base.OnNamespaceDeclaration(node);
Check(node);
}
public override void OnImport(Import node)
{
base.OnImport(node);
Check(node);
}
public override void OnModule(Module node)
{
base.OnModule(node);
Check(node);
}
public override void OnClassDefinition(ClassDefinition node)
{
base.OnClassDefinition(node);
Check(node);
}
public override void OnStructDefinition(StructDefinition node)
{
base.OnStructDefinition(node);
Check(node);
}
public override void OnInterfaceDefinition(InterfaceDefinition node)
{
base.OnInterfaceDefinition(node);
Check(node);
}
public override void OnEnumDefinition(EnumDefinition node)
{
base.OnEnumDefinition(node);
Check(node);
}
public override void OnEnumMember(EnumMember node)
{
base.OnEnumMember(node);
Check(node);
}
public override void OnField(Field node)
{
base.OnField(node);
Check(node);
}
public override void OnProperty(Property node)
{
base.OnProperty(node);
Check(node);
}
public override void OnEvent(Event node)
{
base.OnEvent(node);
Check(node);
}
public override void OnLocal(Local node)
{
base.OnLocal(node);
Check(node);
}
public override void OnBlockExpression(BlockExpression node)
{
base.OnBlockExpression(node);
Check(node);
}
public override void OnMethod(Method node)
{
base.OnMethod(node);
Check(node);
}
public override void OnConstructor(Constructor node)
{
base.OnConstructor(node);
Check(node);
}
public override void OnDestructor(Destructor node)
{
base.OnDestructor(node);
Check(node);
}
public override void OnParameterDeclaration(ParameterDeclaration node)
{
base.OnParameterDeclaration(node);
Check(node);
}
public override void OnGenericParameterDeclaration(GenericParameterDeclaration node)
{
base.OnGenericParameterDeclaration(node);
Check(node);
}
public override void OnDeclaration(Declaration node)
{
base.OnDeclaration(node);
Check(node);
}
public override void OnAttribute(Attribute node)
{
base.OnAttribute(node);
Check(node);
}
public override void OnStatementModifier(StatementModifier node)
{
base.OnStatementModifier(node);
Check(node);
}
public override void OnGotoStatement(GotoStatement node)
{
base.OnGotoStatement(node);
Check(node);
}
public override void OnLabelStatement(LabelStatement node)
{
base.OnLabelStatement(node);
Check(node);
}
public override void OnBlock(Block node)
{
base.OnBlock(node);
Check(node);
}
public override void OnDeclarationStatement(DeclarationStatement node)
{
base.OnDeclarationStatement(node);
Check(node);
}
public override void OnMacroStatement(MacroStatement node)
{
base.OnMacroStatement(node);
Check(node);
}
public override void OnTryStatement(TryStatement node)
{
base.OnTryStatement(node);
Check(node);
}
public override void OnExceptionHandler(ExceptionHandler node)
{
base.OnExceptionHandler(node);
Check(node);
}
public override void OnIfStatement(IfStatement node)
{
base.OnIfStatement(node);
Check(node);
}
public override void OnUnlessStatement(UnlessStatement node)
{
base.OnUnlessStatement(node);
Check(node);
}
public override void OnForStatement(ForStatement node)
{
base.OnForStatement(node);
Check(node);
}
public override void OnWhileStatement(WhileStatement node)
{
base.OnWhileStatement(node);
Check(node);
}
public override void OnBreakStatement(BreakStatement node)
{
base.OnBreakStatement(node);
Check(node);
}
public override void OnContinueStatement(ContinueStatement node)
{
base.OnContinueStatement(node);
Check(node);
}
public override void OnReturnStatement(ReturnStatement node)
{
base.OnReturnStatement(node);
Check(node);
}
public override void OnYieldStatement(YieldStatement node)
{
base.OnYieldStatement(node);
Check(node);
}
public override void OnRaiseStatement(RaiseStatement node)
{
base.OnRaiseStatement(node);
Check(node);
}
public override void OnUnpackStatement(UnpackStatement node)
{
base.OnUnpackStatement(node);
Check(node);
}
public override void OnExpressionStatement(ExpressionStatement node)
{
base.OnExpressionStatement(node);
Check(node);
}
public override void OnOmittedExpression(OmittedExpression node)
{
base.OnOmittedExpression(node);
Check(node);
}
public override void OnExpressionPair(ExpressionPair node)
{
base.OnExpressionPair(node);
Check(node);
}
public override void OnMethodInvocationExpression(MethodInvocationExpression node)
{
base.OnMethodInvocationExpression(node);
Check(node);
}
public override void OnUnaryExpression(UnaryExpression node)
{
base.OnUnaryExpression(node);
Check(node);
}
public override void OnBinaryExpression(BinaryExpression node)
{
base.OnBinaryExpression(node);
Check(node);
}
public override void OnConditionalExpression(ConditionalExpression node)
{
base.OnConditionalExpression(node);
Check(node);
}
public override void OnReferenceExpression(ReferenceExpression node)
{
base.OnReferenceExpression(node);
Check(node);
}
public override void OnMemberReferenceExpression(MemberReferenceExpression node)
{
base.OnMemberReferenceExpression(node);
Check(node);
}
public override void OnGenericReferenceExpression(GenericReferenceExpression node)
{
base.OnGenericReferenceExpression(node);
Check(node);
}
public override void OnQuasiquoteExpression(QuasiquoteExpression node)
{
base.OnQuasiquoteExpression(node);
Check(node);
}
public override void OnStringLiteralExpression(StringLiteralExpression node)
{
base.OnStringLiteralExpression(node);
Check(node);
}
public override void OnCharLiteralExpression(CharLiteralExpression node)
{
base.OnCharLiteralExpression(node);
Check(node);
}
public override void OnTimeSpanLiteralExpression(TimeSpanLiteralExpression node)
{
base.OnTimeSpanLiteralExpression(node);
Check(node);
}
public override void OnIntegerLiteralExpression(IntegerLiteralExpression node)
{
base.OnIntegerLiteralExpression(node);
Check(node);
}
public override void OnDoubleLiteralExpression(DoubleLiteralExpression node)
{
base.OnDoubleLiteralExpression(node);
Check(node);
}
public override void OnNullLiteralExpression(NullLiteralExpression node)
{
base.OnNullLiteralExpression(node);
Check(node);
}
public override void OnSelfLiteralExpression(SelfLiteralExpression node)
{
base.OnSelfLiteralExpression(node);
Check(node);
}
public override void OnSuperLiteralExpression(SuperLiteralExpression node)
{
base.OnSuperLiteralExpression(node);
Check(node);
}
public override void OnBoolLiteralExpression(BoolLiteralExpression node)
{
base.OnBoolLiteralExpression(node);
Check(node);
}
public override void OnRELiteralExpression(RELiteralExpression node)
{
base.OnRELiteralExpression(node);
Check(node);
}
public override void OnSpliceExpression(SpliceExpression node)
{
base.OnSpliceExpression(node);
Check(node);
}
public override void OnSpliceTypeReference(SpliceTypeReference node)
{
base.OnSpliceTypeReference(node);
Check(node);
}
public override void OnSpliceMemberReferenceExpression(SpliceMemberReferenceExpression node)
{
base.OnSpliceMemberReferenceExpression(node);
Check(node);
}
public override void OnSpliceTypeMember(SpliceTypeMember node)
{
base.OnSpliceTypeMember(node);
Check(node);
}
public override void OnSpliceTypeDefinitionBody(SpliceTypeDefinitionBody node)
{
base.OnSpliceTypeDefinitionBody(node);
Check(node);
}
public override void OnSpliceParameterDeclaration(SpliceParameterDeclaration node)
{
base.OnSpliceParameterDeclaration(node);
Check(node);
}
public override void OnExpressionInterpolationExpression(ExpressionInterpolationExpression node)
{
base.OnExpressionInterpolationExpression(node);
Check(node);
}
public override void OnHashLiteralExpression(HashLiteralExpression node)
{
base.OnHashLiteralExpression(node);
Check(node);
}
public override void OnListLiteralExpression(ListLiteralExpression node)
{
base.OnListLiteralExpression(node);
Check(node);
}
public override void OnCollectionInitializationExpression(CollectionInitializationExpression node)
{
base.OnCollectionInitializationExpression(node);
Check(node);
}
public override void OnArrayLiteralExpression(ArrayLiteralExpression node)
{
base.OnArrayLiteralExpression(node);
Check(node);
}
public override void OnGeneratorExpression(GeneratorExpression node)
{
base.OnGeneratorExpression(node);
Check(node);
}
public override void OnExtendedGeneratorExpression(ExtendedGeneratorExpression node)
{
base.OnExtendedGeneratorExpression(node);
Check(node);
}
public override void OnSlice(Slice node)
{
base.OnSlice(node);
Check(node);
}
public override void OnSlicingExpression(SlicingExpression node)
{
base.OnSlicingExpression(node);
Check(node);
}
public override void OnTryCastExpression(TryCastExpression node)
{
base.OnTryCastExpression(node);
Check(node);
}
public override void OnCastExpression(CastExpression node)
{
base.OnCastExpression(node);
Check(node);
}
public override void OnTypeofExpression(TypeofExpression node)
{
base.OnTypeofExpression(node);
Check(node);
}
public override void OnCustomStatement(CustomStatement node)
{
base.OnCustomStatement(node);
Check(node);
}
public override void OnCustomExpression(CustomExpression node)
{
base.OnCustomExpression(node);
Check(node);
}
public override void OnStatementTypeMember(StatementTypeMember node)
{
base.OnStatementTypeMember(node);
Check(node);
}
}
}

Просмотреть файл

@ -61,7 +61,7 @@ namespace UnityScript2CSharp
DumpScripts("Plugin/Editor", pluginEditorScritps);
}
var converter = new UnityScript2CSharpConverter(options.Value.IgnoreErrors);
var converter = new UnityScript2CSharpConverter(options.Value.IgnoreErrors, options.Value.SkipComments, options.Value.ShowOrphanComments);
var references = AssemblyReferencesFrom(options);

Просмотреть файл

@ -24,25 +24,12 @@ namespace UnityScript2CSharp.Steps
base.OnModule(node);
foreach (var comment in _sourceComments.ToArray())
{
var attachedComments = GetAttachedCommentsFrom(comment.BestCandidate);
attachedComments.Add(comment);
_sourceComments.Remove(comment);
}
AttachRemainingComments(node);
}
public override void LeaveMethod(Method node)
{
foreach (var comment in _sourceComments.ToArray())
{
var attachedComments = GetAttachedCommentsFrom(comment.BestCandidate);
attachedComments.Add(comment);
_sourceComments.Remove(comment);
}
AttachRemainingComments(node);
base.LeaveMethod(node);
}
@ -58,8 +45,11 @@ namespace UnityScript2CSharp.Steps
var commentsAboveNode = _sourceComments.Where(candidate => candidate.Token.getLine() < node.LexicalInfo.Line).ToArray();
foreach (var comment in commentsAboveNode)
{
comment.BestCandidate = comment.BestCandidate ?? node;
comment.AnchorKind = AnchorKind.Above;
if (comment.BestCandidate == null)
{
comment.BestCandidate = node;
comment.AnchorKind = AnchorKind.Above;
}
var attachedComments = GetAttachedCommentsFrom(comment.BestCandidate);
attachedComments.Add(comment);
@ -67,6 +57,10 @@ namespace UnityScript2CSharp.Steps
_sourceComments.Remove(comment);
}
if (node.Entity != null && node.Entity.FullName == "Boo.Lang.Builtins.array")
return;
// Handle comments in the same line
var foundOnSameLine = _sourceComments.Where(candidate => candidate.Token.getLine() == node.LexicalInfo.Line);
foreach (var comment in foundOnSameLine)
@ -75,55 +69,79 @@ namespace UnityScript2CSharp.Steps
{
comment.BestCandidate = node;
comment.Distance = Int32.MaxValue;
continue;
}
int distance = 0;
if (node.LexicalInfo.Column > comment.Token.getColumn()) // comment is on left of the AST node
{
var endOfCommentCollumn = comment.Token.getColumn() + comment.Token.getText().Length;
var distance = node.LexicalInfo.Column - endOfCommentCollumn;
if (distance <= comment.Distance)
distance = node.LexicalInfo.Column - endOfCommentCollumn;
if (distance <= comment.Distance && distance >= 0)
{
comment.BestCandidate = node;
comment.Distance = distance;
comment.AnchorKind = AnchorKind.Left;
}
}
else
// comment sould be on RIGHT of the AST node
var endOfNodeColumn = EndColumnOf(node);
distance = comment.Token.getColumn() - endOfNodeColumn;
if (distance <= comment.Distance && (distance >= 0 || comment.CommentKind == CommentKind.SingleLine))
{
// comment is on RIGHT of the AST node
var endOfNodeColumn = node.LexicalInfo.Column + TokenLengthFor(node);
var distance = comment.Token.getColumn() - endOfNodeColumn;
if (distance <= comment.Distance)
{
comment.BestCandidate= node;
comment.Distance = distance;
comment.AnchorKind = AnchorKind.Right;
}
comment.BestCandidate = node;
comment.Distance = distance;
comment.AnchorKind = AnchorKind.Right;
}
}
base.OnNode(node);
}
private void AttachRemainingComments(Node node)
{
if (!node.EndSourceLocation.IsValid)
return;
foreach (var comment in _sourceComments.Where(comment => comment.Token.getLine() <= node.EndSourceLocation.Line).ToArray())
{
if (comment.BestCandidate == null)
{
comment.BestCandidate = node;
comment.AnchorKind = AnchorKind.Below;
}
var attachedComments = GetAttachedCommentsFrom(comment.BestCandidate);
attachedComments.Add(comment);
_sourceComments.Remove(comment);
}
}
private IList<Comment> GetAttachedCommentsFrom(Node node)
{
if (!node.ContainsAnnotation(COMMENTS_KEY))
{
node.Annotate(COMMENTS_KEY, new List<Comment>());
node.Annotate(COMMENTS_KEY, new System.Collections.Generic.List<Comment>());
}
return (IList<Comment>) node[COMMENTS_KEY];
}
private int TokenLengthFor(Node node)
// This method returns an aproximation for the *end column* of the passed node.
private int EndColumnOf(Node node)
{
switch (node.NodeType)
{
case NodeType.ReturnStatement: return "return".Length;
case NodeType.BinaryExpression: return ((BinaryExpression) node).Left.LexicalInfo.Column + node.ToString().Length;
case NodeType.ReturnStatement: return node.LexicalInfo.Column + "return".Length;
case NodeType.IfStatement:
{
var condition = ((IfStatement)node).Condition;
return condition.LexicalInfo.Column + condition.ToString().Length + 1; // consider the ')' after the condition
}
}
return node.ToString().Length;
return node.LexicalInfo.Column + node.ToString().Length;
}
}
}

Просмотреть файл

@ -110,6 +110,7 @@
<Compile Include="AnchorKind.cs" />
<Compile Include="Comment.cs" />
<Compile Include="CommentKind.cs" />
<Compile Include="OrphanCommentVisitor.cs" />
<Compile Include="Steps\AttachComments.cs" />
<Compile Include="BlockIdentation.cs" />
<Compile Include="CommandLineArguments.cs" />

Просмотреть файл

@ -20,15 +20,20 @@ namespace UnityScript2CSharp
class UnityScript2CSharpConverter
{
private readonly bool _ignoreErrors;
private readonly bool _skipComments;
private readonly bool _checkOrphanComments;
public UnityScript2CSharpConverter(bool ignoreErrors = false)
public UnityScript2CSharpConverter(bool ignoreErrors = false, bool skipComments = false, bool checkOrphanComments = true)
{
_ignoreErrors = ignoreErrors;
_skipComments = skipComments;
_checkOrphanComments = checkOrphanComments;
}
public void Convert(IEnumerable<SourceFile> inputs, IEnumerable<string> definedSymbols, IEnumerable<string> referencedAssemblies, Action<string, string, int> onScriptConverted)
{
var comp = CreatAndInitializeCompiler(inputs, definedSymbols, referencedAssemblies);
var comments = CollectCommentsFrom(inputs, definedSymbols);
var comp = CreatAndInitializeCompiler(inputs, definedSymbols, referencedAssemblies, comments);
var result = comp.Run();
HandleCompilationResult(result);
@ -36,14 +41,20 @@ namespace UnityScript2CSharp
var visitor = new UnityScript2CSharpConverterVisitor();
visitor.ScriptConverted += onScriptConverted;
result.CompileUnit.Accept(visitor);
if (_checkOrphanComments)
result.CompileUnit.Accept(new OrphanCommentVisitor());
}
private IDictionary<string, IList<Comment>> CollectCommentsFrom(IEnumerable<SourceFile> inputs, IEnumerable<string> definedSymbols)
{
var comments = new Dictionary<string, IList<Comment>>();
foreach (var source in inputs)
if (!_skipComments)
{
comments[source.FileName] = CollectCommentsFor(source, definedSymbols);
foreach (var source in inputs)
{
comments[source.FileName] = CollectCommentsFor(source, definedSymbols);
}
}
return comments;
@ -68,18 +79,10 @@ namespace UnityScript2CSharp
IToken last = null;
while (token != null && token.Type != UnityScriptLexer.EOF)
{
IToken next = null;
try
{
if (token.Type == UnityScriptLexer.SL_COMMENT || token.Type == UnityScriptLexer.ML_COMMENT)
{
next = lexer.nextToken();
if (next.getLine() > token.getLine())
{
token.setText(token.getText() + Environment.NewLine);
}
comments.Add(new Comment(token, token.Type == UnityScriptLexer.SL_COMMENT ? CommentKind.SingleLine : CommentKind.MultipleLine, last));
}
else
last = token;
}
@ -91,7 +94,7 @@ namespace UnityScript2CSharp
{
try
{
token = next ?? lexer.nextToken();
token = lexer.nextToken();
}
catch (TokenStreamRecognitionException tre)
{
@ -129,11 +132,10 @@ namespace UnityScript2CSharp
CompilerWarnings = CompilerWarnings ?? new List<string>();
}
internal UnityScriptCompiler CreatAndInitializeCompiler(IEnumerable<SourceFile> inputs, IEnumerable<string> definedSymbols, IEnumerable<string> referencedAssemblies)
internal UnityScriptCompiler CreatAndInitializeCompiler(IEnumerable<SourceFile> inputs, IEnumerable<string> definedSymbols, IEnumerable<string> referencedAssemblies, IDictionary<string, IList<Comment>> comments)
{
_compiler = new UnityScriptCompiler();
_compiler.Parameters.TabSize = 4;
var comments = CollectCommentsFrom(inputs, definedSymbols);
SetupCompilerParameters(definedSymbols, referencedAssemblies);
SetupCompilerPipeline(comments);
@ -226,7 +228,9 @@ namespace UnityScript2CSharp
adjustedPipeline.Add(new PromoteImplicitBooleanConversionsToExplicitComparisons());
adjustedPipeline.Add(new InstanceToTypeReferencedStaticMemberReference());
adjustedPipeline.Add(new TransforwmKnownUnityEngineMethods());
adjustedPipeline.Add(new AttachComments(comments));
if (!_skipComments)
adjustedPipeline.Add(new AttachComments(comments));
_compiler.Parameters.Pipeline = adjustedPipeline;
}

Просмотреть файл

@ -44,12 +44,12 @@ namespace UnityScript2CSharp
public override void OnSimpleTypeReference(SimpleTypeReference node)
{
HandleComments(node, AnchorKind.Left);
WriteComments(node, AnchorKind.Left);
var typeName = TypeNameFor(node.Entity);
_writer.Write(typeName ?? node.Name);
HandleComments(node, AnchorKind.Right);
WriteComments(node, AnchorKind.Right);
}
private void _builderAppendIdented(string str)
@ -75,12 +75,20 @@ namespace UnityScript2CSharp
public override void OnArrayTypeReference(ArrayTypeReference node)
{
WriteComments(node, AnchorKind.Above);
WriteComments(node, AnchorKind.Left);
node.ElementType.Accept(this);
_writer.Write($"[{new String(',', (int) (node.Rank.Value -1))}]");
WriteComments(node, AnchorKind.Right);
}
public override void OnCallableTypeReference(CallableTypeReference node)
{
WriteComments(node, AnchorKind.Above);
WriteComments(node, AnchorKind.Left);
var types = new List<TypeReference>(node.Parameters.Select(p => p.Type));
if (node.ReturnType == null)
{
@ -98,6 +106,7 @@ namespace UnityScript2CSharp
WriteCommaSeparatedList(types);
_writer.Write(">");
}
WriteComments(node, AnchorKind.Right);
}
public override void OnGenericTypeReference(GenericTypeReference node)
@ -147,6 +156,9 @@ namespace UnityScript2CSharp
if (IsSyntheticDelegateUsedByCallable(node))
return;
WriteComments(node, AnchorKind.Above);
WriteComments(node, AnchorKind.Left);
_writer.WriteLine("[System.Serializable]"); // Every class in UnityScript is serializable
WriteAttributes(node.Attributes);
@ -159,6 +171,8 @@ namespace UnityScript2CSharp
_writer.WriteLine("{");
WriteMembersOf(node);
_writer.WriteLine("}");
WriteComments(node, AnchorKind.Right);
}
public override void OnStructDefinition(StructDefinition node)
@ -186,8 +200,15 @@ namespace UnityScript2CSharp
public override void OnEnumDefinition(EnumDefinition node)
{
WriteComments(node, AnchorKind.Above);
WriteComments(node, AnchorKind.Left);
_writer.IndentNextWrite = true;
_writer.WriteLine($"{ModifiersToString(node.Modifiers)} enum {node.Name}");
_writer.Write($"{ModifiersToString(node.Modifiers)} enum {node.Name}");
WriteComments(node, AnchorKind.Right);
_writer.WriteLine();
_writer.WriteLine("{");
using (new BlockIdentation(_writer))
{
@ -203,16 +224,24 @@ namespace UnityScript2CSharp
public override void OnEnumMember(EnumMember node)
{
WriteComments(node, AnchorKind.Above);
WriteComments(node, AnchorKind.Left);
_writer.Write(node.Name);
if (node.Initializer != null)
{
_writer.Write(" = ");
node.Initializer.Accept(this);
}
WriteComments(node, AnchorKind.Right);
}
public override void OnField(Field node)
{
WriteComments(node, AnchorKind.Above);
WriteComments(node, AnchorKind.Left);
WriteAttributes(node.Attributes);
_builderAppend(ModifiersToString(node.Modifiers));
@ -226,6 +255,8 @@ namespace UnityScript2CSharp
_builderAppend(" = ");
}
WriteComments(node, AnchorKind.Right);
_writer.WriteLine(";");
}
@ -256,10 +287,14 @@ namespace UnityScript2CSharp
public override void OnMethod(Method node)
{
HandleComments(node, AnchorKind.Above);
WriteComments(node, AnchorKind.Above);
WriteComments(node, AnchorKind.Left);
if (node.Name == "Main" || node.IsSynthetic)
{
WriteComments(node, AnchorKind.Below);
return;
}
WriteAttributes(node.Attributes);
@ -273,10 +308,14 @@ namespace UnityScript2CSharp
_builderAppend(node.Name);
WriteParameterList(node.Parameters);
WriteComments(node, AnchorKind.Right);
if (isInterface)
_writer.WriteLine(";");
else
node.Body.Accept(this);
WriteComments(node, AnchorKind.Below);
}
public override bool EnterBlock(Block node)
@ -311,6 +350,9 @@ namespace UnityScript2CSharp
public override void OnConstructor(Constructor node)
{
WriteComments(node, AnchorKind.Above);
WriteComments(node, AnchorKind.Left);
var stmts = CtorStatementsWithoutParameterlessSuperInvocation(node);
if (stmts.Count == 0)
return;
@ -325,6 +367,8 @@ namespace UnityScript2CSharp
WriteCtorChainningFor(node);
WriteComments(node, AnchorKind.Right);
node.Body.Accept(this);
}
@ -336,9 +380,14 @@ namespace UnityScript2CSharp
public override void OnParameterDeclaration(ParameterDeclaration node)
{
WriteComments(node, AnchorKind.Above);
WriteComments(node, AnchorKind.Left);
node.Type.Accept(this);
_builderAppend(' ');
_builderAppend(node.Name);
WriteComments(node, AnchorKind.Right);
}
public override void OnGenericParameterDeclaration(GenericParameterDeclaration node)
@ -373,6 +422,9 @@ namespace UnityScript2CSharp
public override void OnAttribute(Attribute node)
{
WriteComments(node, AnchorKind.Above);
WriteComments(node, AnchorKind.Left);
if (node.Name == "System.SerializableAttribute")
return;
@ -397,6 +449,8 @@ namespace UnityScript2CSharp
_writer.Write(")");
_writer.WriteLine("]");
WriteComments(node, AnchorKind.Right);
}
public override void OnStatementModifier(StatementModifier node)
@ -462,10 +516,15 @@ namespace UnityScript2CSharp
public override void OnIfStatement(IfStatement node)
{
WriteComments(node, AnchorKind.Above);
WriteComments(node, AnchorKind.Left);
_builderAppendIdented("if (");
node.Condition.Accept(this);
_builderAppend(")");
WriteComments(node, AnchorKind.Right);
node.TrueBlock.Accept(this);
if (node.FalseBlock != null)
{
@ -482,6 +541,9 @@ namespace UnityScript2CSharp
public override void OnForStatement(ForStatement node)
{
WriteComments(node, AnchorKind.Above);
WriteComments(node, AnchorKind.Left);
_writer.Write("foreach (");
VisitPossibleClashingDeclaration(node.Declarations[0]);
@ -489,42 +551,56 @@ namespace UnityScript2CSharp
node.Iterator.Accept(this);
_writer.Write(")");
WriteComments(node, AnchorKind.Right);
node.Block.Accept(this);
}
public override void OnWhileStatement(WhileStatement node)
{
WriteComments(node, AnchorKind.Above);
WriteComments(node, AnchorKind.Left);
_builderAppendIdented("while (");
node.Condition.Accept(this);
_builderAppend(")");
WriteComments(node, AnchorKind.Right);
node.Block.Accept(this);
}
public override void OnBreakStatement(BreakStatement node)
{
HandleComments(node, AnchorKind.Left);
WriteComments(node, AnchorKind.Above);
WriteComments(node, AnchorKind.Left);
_writer.WriteLine("break;");
HandleComments(node, AnchorKind.Right);
WriteComments(node, AnchorKind.Right);
}
public override void OnContinueStatement(ContinueStatement node)
{
HandleComments(node, AnchorKind.Left);
WriteComments(node, AnchorKind.Above);
WriteComments(node, AnchorKind.Left);
_writer.WriteLine("continue;");
HandleComments(node, AnchorKind.Right);
WriteComments(node, AnchorKind.Right);
}
public override void OnReturnStatement(ReturnStatement node)
{
HandleComments(node, AnchorKind.Above);
HandleComments(node, AnchorKind.Left);
WriteComments(node, AnchorKind.Above);
WriteComments(node, AnchorKind.Left);
if (TryHandleYieldBreak(node))
return;
_builderAppendIdented("return");
HandleComments(node, AnchorKind.Right);
WriteComments(node, AnchorKind.Right);
if (node.Expression != null)
{
@ -537,6 +613,9 @@ namespace UnityScript2CSharp
public override void OnYieldStatement(YieldStatement node)
{
WriteComments(node, AnchorKind.Above);
WriteComments(node, AnchorKind.Left);
_writer.Write("yield return ");
if (node.Expression != null)
node.Expression.Accept(this);
@ -544,6 +623,8 @@ namespace UnityScript2CSharp
_writer.Write("null");
_writer.WriteLine(";");
WriteComments(node, AnchorKind.Right);
}
public override void OnRaiseStatement(RaiseStatement node)
@ -560,11 +641,15 @@ namespace UnityScript2CSharp
public override void OnExpressionStatement(ExpressionStatement node)
{
WriteComments(node, AnchorKind.Above);
WriteComments(node, AnchorKind.Left);
node.Expression.Accept(this);
if (!_lastIgnored)
_writer.WriteLine(";");
_lastIgnored = false;
WriteComments(node, AnchorKind.Right);
}
public override void OnOmittedExpression(OmittedExpression node)
@ -575,14 +660,22 @@ namespace UnityScript2CSharp
public override void OnExpressionPair(ExpressionPair node)
{
WriteComments(node, AnchorKind.Above);
WriteComments(node, AnchorKind.Left);
node.First.Accept(this);
_writer.Write(" = ");
node.Second.Accept(this);
WriteComments(node, AnchorKind.Right);
}
public override void OnMethodInvocationExpression(MethodInvocationExpression node)
{
if (node.Target.Entity != null && node.Target.Entity.EntityType == EntityType.BuiltinFunction)
WriteComments(node, AnchorKind.Above);
WriteComments(node, AnchorKind.Left);
if (node.Target.Entity != null && node.Target.Entity.EntityType == EntityType.BuiltinFunction && node.Target.Entity != BuiltinFunction.Quack)
{
_lastIgnored = true;
return;
@ -618,6 +711,8 @@ namespace UnityScript2CSharp
WriteParameterList(node.Arguments, refOutWriter);
_brackets.Pop();
WriteComments(node, AnchorKind.Right);
}
private void HandleNewExpression(MethodInvocationExpression node)
@ -630,6 +725,9 @@ namespace UnityScript2CSharp
public override void OnUnaryExpression(UnaryExpression node)
{
WriteComments(node, AnchorKind.Above);
WriteComments(node, AnchorKind.Left);
bool postOperator = AstUtil.IsPostUnaryOperator(node.Operator);
var operatorText = node.Operator == UnaryOperatorType.LogicalNot ? "!" : BooPrinterVisitor.GetUnaryOperatorText(node.Operator);
if (!postOperator)
@ -641,10 +739,15 @@ namespace UnityScript2CSharp
{
_builderAppend(operatorText);
}
WriteComments(node, AnchorKind.Right);
}
public override void OnBinaryExpression(BinaryExpression node)
{
WriteComments(node, AnchorKind.Above);
WriteComments(node, AnchorKind.Left);
var needParensAround = node.Operator != BinaryOperatorType.Assign;
if (needParensAround)
{
@ -671,10 +774,15 @@ namespace UnityScript2CSharp
_writer.Write($" {CSharpOperatorFor(node.Operator)} ");
node.Right.Accept(this);
});
WriteComments(node, AnchorKind.Right);
}
public override void OnConditionalExpression(ConditionalExpression node)
{
WriteComments(node, AnchorKind.Above);
WriteComments(node, AnchorKind.Left);
var parent = node.ParentNode as BinaryExpression;
var needsParens = parent != null && (parent.Right != node || parent.Operator != BinaryOperatorType.Assign);
@ -686,15 +794,21 @@ namespace UnityScript2CSharp
_writer.Write(" : ");
VisitWrapping(node.FalseValue, node.FalseValue.NodeType == NodeType.ConditionalExpression, "(", ")");
});
WriteComments(node, AnchorKind.Right);
}
public override void OnReferenceExpression(ReferenceExpression node)
{
WriteComments(node, AnchorKind.Above);
WriteComments(node, AnchorKind.Left);
if (node.ContainsAnnotation("VALUE_TYPE_INITIALIZATON_MARKER"))
{
_writer.Write("default(");
_writer.Write(TypeNameFor(node.Entity) ?? node.Name);
_writer.Write(")");
WriteComments(node, AnchorKind.Right);
return;
}
@ -702,16 +816,26 @@ namespace UnityScript2CSharp
_writer.Write("object");
else
_writer.Write(TypeNameFor(node.Entity) ?? node.Name);
WriteComments(node, AnchorKind.Right);
}
public override void OnMemberReferenceExpression(MemberReferenceExpression node)
{
WriteComments(node, AnchorKind.Above);
WriteComments(node, AnchorKind.Left);
node.Target.Accept(this);
_builderAppend($".{node.Name}");
WriteComments(node, AnchorKind.Right);
}
public override void OnGenericReferenceExpression(GenericReferenceExpression node)
{
WriteComments(node, AnchorKind.Above);
WriteComments(node, AnchorKind.Left);
if (node.IsArrayInstantiation())
{
_writer.Write("new ");
@ -731,6 +855,8 @@ namespace UnityScript2CSharp
_writer.Write(", ");
}
_writer.Write(">");
WriteComments(node, AnchorKind.Right);
}
public override void OnQuasiquoteExpression(QuasiquoteExpression node)
@ -760,9 +886,10 @@ namespace UnityScript2CSharp
value.Replace(replacement.Key, replacement.Value);
}
HandleComments(node, AnchorKind.Left);
WriteComments(node, AnchorKind.Above);
WriteComments(node, AnchorKind.Left);
_writer.Write($"\"{value}\"");
HandleComments(node, AnchorKind.Right);
WriteComments(node, AnchorKind.Right);
}
public override void OnCharLiteralExpression(CharLiteralExpression node)
@ -779,44 +906,50 @@ namespace UnityScript2CSharp
public override void OnIntegerLiteralExpression(IntegerLiteralExpression node)
{
HandleComments(node, AnchorKind.Left);
WriteComments(node, AnchorKind.Above);
WriteComments(node, AnchorKind.Left);
_writer.Write(node.Value);
HandleComments(node, AnchorKind.Right);
WriteComments(node, AnchorKind.Right);
}
public override void OnDoubleLiteralExpression(DoubleLiteralExpression node)
{
HandleComments(node, AnchorKind.Left);
WriteComments(node, AnchorKind.Above);
WriteComments(node, AnchorKind.Left);
_writer.Write($"{node.Value.ToString(System.Globalization.CultureInfo.InvariantCulture)}f");
HandleComments(node, AnchorKind.Right);
WriteComments(node, AnchorKind.Right);
}
public override void OnNullLiteralExpression(NullLiteralExpression node)
{
HandleComments(node, AnchorKind.Left);
WriteComments(node, AnchorKind.Above);
WriteComments(node, AnchorKind.Left);
_builderAppend("null");
HandleComments(node, AnchorKind.Right);
WriteComments(node, AnchorKind.Right);
}
public override void OnSelfLiteralExpression(SelfLiteralExpression node)
{
HandleComments(node, AnchorKind.Left);
WriteComments(node, AnchorKind.Above);
WriteComments(node, AnchorKind.Left);
_writer.Write("this");
HandleComments(node, AnchorKind.Right);
WriteComments(node, AnchorKind.Right);
}
public override void OnSuperLiteralExpression(SuperLiteralExpression node)
{
HandleComments(node, AnchorKind.Left);
WriteComments(node, AnchorKind.Above);
WriteComments(node, AnchorKind.Left);
_writer.Write("base");
HandleComments(node, AnchorKind.Right);
WriteComments(node, AnchorKind.Right);
}
public override void OnBoolLiteralExpression(BoolLiteralExpression node)
{
HandleComments(node, AnchorKind.Left);
WriteComments(node, AnchorKind.Above);
WriteComments(node, AnchorKind.Left);
_writer.Write(node.Value ? "true" : "false");
HandleComments(node, AnchorKind.Right);
WriteComments(node, AnchorKind.Right);
}
public override void OnRELiteralExpression(RELiteralExpression node)
@ -869,6 +1002,9 @@ namespace UnityScript2CSharp
public override void OnHashLiteralExpression(HashLiteralExpression node)
{
WriteComments(node, AnchorKind.Above);
WriteComments(node, AnchorKind.Left);
_writer.Write("new Hashtable() {");
foreach (var item in node.Items)
{
@ -879,6 +1015,8 @@ namespace UnityScript2CSharp
_writer.Write(" }, ");
}
_writer.Write("}");
WriteComments(node, AnchorKind.Right);
}
public override void OnListLiteralExpression(ListLiteralExpression node)
@ -916,23 +1054,36 @@ namespace UnityScript2CSharp
public override void OnSlicingExpression(SlicingExpression node)
{
WriteComments(node, AnchorKind.Above);
WriteComments(node, AnchorKind.Left);
node.Target.Accept(this);
_writer.Write("[");
WriteCommaSeparatedList(node.Indices);
_writer.Write("]");
WriteComments(node, AnchorKind.Right);
}
public override void OnTryCastExpression(TryCastExpression node)
{
var isTargetOfMemberReferenceExpression = NeedParensAround(node);
WriteComments(node, AnchorKind.Above);
WriteComments(node, AnchorKind.Left);
VisitWrapping(node.Target, isTargetOfMemberReferenceExpression, "(");
_writer.Write(" as ");
VisitWrapping(node.Type, isTargetOfMemberReferenceExpression, posfix: ")");
WriteComments(node, AnchorKind.Right);
}
public override void OnCastExpression(CastExpression node)
{
WriteComments(node, AnchorKind.Above);
WriteComments(node, AnchorKind.Left);
WrapWith(NeedParensAround(node), "(", ")", delegate
{
_writer.Write("(");
@ -944,13 +1095,20 @@ namespace UnityScript2CSharp
node.Target.Accept(this);
});
});
WriteComments(node, AnchorKind.Right);
}
public override void OnTypeofExpression(TypeofExpression node)
{
WriteComments(node, AnchorKind.Above);
WriteComments(node, AnchorKind.Left);
_writer.Write("typeof(");
node.Type.Accept(this);
_writer.Write(")");
WriteComments(node, AnchorKind.Right);
}
public override void OnCustomStatement(CustomStatement node)
@ -978,9 +1136,9 @@ namespace UnityScript2CSharp
if (isReturningIEnumerable)
{
HandleComments(node, AnchorKind.Left);
WriteComments(node, AnchorKind.Left);
_writer.Write("yield break;");
HandleComments(node, AnchorKind.Right);
WriteComments(node, AnchorKind.Right);
_writer.WriteLine();
}
@ -1335,7 +1493,7 @@ namespace UnityScript2CSharp
return "Label" + label.Replace("$", "_");
}
private void HandleComments(Node node, AnchorKind anchorKind)
private void WriteComments(Node node, AnchorKind anchorKind)
{
if (!node.ContainsAnnotation(COMMENT_KEY))
return;
@ -1353,6 +1511,9 @@ namespace UnityScript2CSharp
_writer.WriteBeforeNextNewLine(commentText);
else
_writer.Write(commentText);
if (comment.AnchorKind == AnchorKind.Above)
_writer.WriteLine();
}
if (comments.Count == 0)

Просмотреть файл

@ -7,7 +7,7 @@ namespace UnityScript2CSharp
{
private StringBuilder _builder;
private int _indentation;
private string _x;
private string _toBeWrittenBeforeNextNewLine;
private static readonly string _newLine = Environment.NewLine;
public Writer(string contents)
@ -49,10 +49,10 @@ namespace UnityScript2CSharp
public void WriteLine()
{
if (_x != null)
if (_toBeWrittenBeforeNextNewLine != null)
{
_builder.Append(_x);
_x = null;
_builder.Append(_toBeWrittenBeforeNextNewLine);
_toBeWrittenBeforeNextNewLine = null;
}
_builder.Append(_newLine);
@ -66,7 +66,7 @@ namespace UnityScript2CSharp
}
public void WriteBeforeNextNewLine(string text)
{
_x = text;
_toBeWrittenBeforeNextNewLine = text;
}
public static string NewLine { get { return _newLine; } }