basic support for locals & if statement

This commit is contained in:
Adriano Carlos Verona 2017-06-02 14:38:00 -03:00
Родитель e7aa04ef29
Коммит ca421e4b14
14 изменённых файлов: 360 добавлений и 87 удалений

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

@ -13,6 +13,15 @@ namespace UnityScript2CSharp.Tests
AssertConversion(sourceFiles, expectedConvertedContents);
}
[Test]
public void If_Else()
{
var sourceFiles = SingleSourceFor("if_else_statement.js", "function F(b:boolean) { if (b) return 1; else return 2; }");
var expectedConvertedContents = SingleSourceFor("if_else_statement.cs", DefaultUsings + @" public partial class if_else_statement : MonoBehaviour { public virtual int F(bool b) { if (b) { return 1; } else { return 2; } } }");
AssertConversion(sourceFiles, expectedConvertedContents);
}
[Test]
public void Return_Void()
{

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

@ -2,6 +2,8 @@ using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Text.RegularExpressions;
using Microsoft.Win32;
using NUnit.Framework;
namespace UnityScript2CSharp.Tests
@ -12,5 +14,77 @@ namespace UnityScript2CSharp.Tests
{
return new[] { new SourceFile { FileName = fileName, Contents = contents } };
}
private static string UnityInstallFolder
{
get
{
var installFolder = Environment.GetEnvironmentVariable("UNITY_INSTALL_FOLDER");
if (installFolder != null)
return installFolder;
switch (Environment.OSVersion.Platform)
{
case PlatformID.MacOSX:
return "";
case PlatformID.Unix:
return "";
}
var installKey = Registry.CurrentUser.OpenSubKey(@"Software\Unity Technologies\Installer\Unity\");
if (installKey != null)
{
installFolder = (string) installKey.GetValue("Location x64");
if (installFolder != null)
return Path.Combine(installFolder, "Editor/");
}
throw new Exception("Could not find Unity installation.");
}
}
private static void AssertConversion(IList<SourceFile> sourceFiles, IList<SourceFile> expectedConverted)
{
var tempFolder = Path.Combine(Path.GetTempPath(), "UnityScript2CSharpConversionTests", SavePathFrom(TestContext.CurrentContext.Test.Name));
Console.WriteLine("Converted files saved to: {0}", tempFolder);
var converter = new UnityScript2CSharpConverter();
converter.Convert(
tempFolder,
sourceFiles,
new[] { "MY_DEFINE" },
new[]
{
typeof(object).Assembly.Location,
$@"{UnityInstallFolder}Data\Managed\UnityEngine.dll",
$@"{UnityInstallFolder}Data\Managed\UnityEditor.dll",
});
var r = new Regex("\\s{2,}|\\r\\n", RegexOptions.Multiline | RegexOptions.Compiled);
for (int i = 0; i < sourceFiles.Count; i++)
{
var convertedFilePath = Path.Combine(tempFolder, expectedConverted[i].FileName);
Assert.That(File.Exists(convertedFilePath), Is.True);
var generatedScript = File.ReadAllText(convertedFilePath);
generatedScript = r.Replace(generatedScript, " ");
Assert.That(generatedScript, Is.EqualTo(expectedConverted[i].Contents), Environment.NewLine + "Converted: " + Environment.NewLine + generatedScript + Environment.NewLine);
}
}
private static string SavePathFrom(string testName)
{
var sb = new StringBuilder(testName);
foreach (var invalidPathChar in Path.GetInvalidFileNameChars())
{
sb.Replace(invalidPathChar, '_');
}
return sb.ToString();
}
private const string DefaultUsings = "using UnityEngine; using UnityEditor; using System.Collections;";
private const string DefaultGeneratedClass = DefaultUsings + " public partial class ";
}
}

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

@ -1,8 +1,3 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Text.RegularExpressions;
using NUnit.Framework;
namespace UnityScript2CSharp.Tests
@ -150,6 +145,42 @@ namespace UnityScript2CSharp.Tests
{
}
[Test]
public void Locals_Infered_Type()
{
var sourceFiles = SingleSourceFor("locals_inferred.js", "function F() { var i = 2; }");
var expectedConvertedContents = SingleSourceFor("locals_inferred.cs", DefaultGeneratedClass + "locals_inferred : MonoBehaviour { public virtual void F() { int i = 2; } }");
AssertConversion(sourceFiles, expectedConvertedContents);
}
[Test]
public void Locals()
{
var sourceFiles = SingleSourceFor("locals.js", "function F() { var i:int; }");
var expectedConvertedContents = SingleSourceFor("locals.cs", DefaultGeneratedClass + "locals : MonoBehaviour { public virtual void F() { int i; } }");
AssertConversion(sourceFiles, expectedConvertedContents);
}
[Test]
public void Locals_With_Initializers()
{
var sourceFiles = SingleSourceFor("locals_initializers.js", "function F() { var i:int = 1; }");
var expectedConvertedContents = SingleSourceFor("locals_initializers.cs", DefaultGeneratedClass + "locals_initializers : MonoBehaviour { public virtual void F() { int i = 1; } }");
AssertConversion(sourceFiles, expectedConvertedContents);
}
[Test]
public void Locals_With_Custom_Type()
{
var sourceFiles = SingleSourceFor("locals_custom.js", "class C { function F() { var c:C; } }");
var expectedConvertedContents = SingleSourceFor("locals_custom.cs", DefaultUsings + " public class C : object { public virtual void F() { C c; } }");
AssertConversion(sourceFiles, expectedConvertedContents);
}
[Test]
public void Generic_Methods()
{
@ -192,47 +223,5 @@ namespace UnityScript2CSharp.Tests
public void Scripts_In_Plugin_Folder_Works()
{
}
private static void AssertConversion(IList<SourceFile> sourceFiles, IList<SourceFile> expectedConverted)
{
var tempFolder = Path.Combine(Path.GetTempPath(), "UnityScript2CSharpConversionTests", SavePathFrom(TestContext.CurrentContext.Test.Name));
Console.WriteLine("Converted files saved to: {0}", tempFolder);
var converter = new UnityScript2CSharpConverter();
converter.Convert(
tempFolder,
sourceFiles,
new[] { "MY_DEFINE" },
new[]
{
typeof(object).Assembly.Location,
@"M:\Work\Repo\UnityTrunk\build\WindowsEditor\Data\Managed\UnityEngine.dll",
@"M:\Work\Repo\UnityTrunk\build\WindowsEditor\Data\Managed\UnityEditor.dll",
});
var r = new Regex("\\s{2,}|\\r\\n", RegexOptions.Multiline | RegexOptions.Compiled);
for (int i = 0; i < sourceFiles.Count; i++)
{
var convertedFilePath = Path.Combine(tempFolder, expectedConverted[i].FileName);
Assert.That(File.Exists(convertedFilePath), Is.True);
var generatedScript = File.ReadAllText(convertedFilePath);
generatedScript = r.Replace(generatedScript, " ");
Assert.That(generatedScript, Is.EqualTo(expectedConverted[i].Contents), Environment.NewLine + "Converted: " + Environment.NewLine + generatedScript + Environment.NewLine);
}
}
private static string SavePathFrom(string testName)
{
var sb = new StringBuilder(testName);
foreach (var invalidPathChar in Path.GetInvalidFileNameChars())
{
sb.Replace(invalidPathChar, '_');
}
return sb.ToString();
}
private const string DefaultUsings = "using UnityEngine; using UnityEditor; using System.Collections;";
}
}

Двоичные данные
UnityScript2CSharp/Libs/Boo.Lang.Compiler.dll Normal file

Двоичный файл не отображается.

Двоичные данные
UnityScript2CSharp/Libs/Boo.Lang.Extensions.dll Normal file

Двоичный файл не отображается.

Двоичные данные
UnityScript2CSharp/Libs/Boo.Lang.Parser.dll Normal file

Двоичный файл не отображается.

Двоичные данные
UnityScript2CSharp/Libs/Boo.Lang.PatternMatching.dll Normal file

Двоичный файл не отображается.

Двоичные данные
UnityScript2CSharp/Libs/Boo.Lang.Useful.dll Normal file

Двоичный файл не отображается.

Двоичные данные
UnityScript2CSharp/Libs/Boo.Lang.dll Normal file

Двоичный файл не отображается.

Двоичные данные
UnityScript2CSharp/Libs/UnityScript.Lang.dll Normal file

Двоичный файл не отображается.

Двоичные данные
UnityScript2CSharp/Libs/UnityScript.dll Normal file

Двоичный файл не отображается.

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

@ -6,7 +6,11 @@ using System.Reflection;
using System.Text;
using Boo.Lang.Compiler;
using Boo.Lang.Compiler.Ast;
using Boo.Lang.Compiler.Ast.Visitors;
using Boo.Lang.Compiler.IO;
using Boo.Lang.Compiler.Steps;
using Boo.Lang.Compiler.TypeSystem;
using Boo.Lang.Compiler.TypeSystem.Internal;
using Boo.Lang.Compiler.TypeSystem.Reflection;
using Boo.Lang.Compiler.TypeSystem.Services;
using Mono.Cecil;
@ -122,17 +126,17 @@ namespace UnityScript2CSharp
{
var pipeline = new Boo.Lang.Compiler.Pipelines.Compile { BreakOnErrors = false };
//pipeline.Remove(typeof(ConstantFolding));
//pipeline.Remove(typeof(ExpandPropertiesAndEvents));
//pipeline.Remove(typeof(CheckNeverUsedMembers));
//pipeline.Remove(typeof(ExpandVarArgsMethodInvocations));
//pipeline.Remove(typeof(InjectCallableConversions));
//pipeline.Remove(typeof(StricterErrorChecking));
//pipeline.Remove(typeof(RemoveDeadCode));
//pipeline.Remove(typeof(OptimizeIterationStatements));
pipeline.Remove(typeof(ConstantFolding));
pipeline.Remove(typeof(ExpandPropertiesAndEvents));
pipeline.Remove(typeof(CheckNeverUsedMembers));
pipeline.Remove(typeof(ExpandVarArgsMethodInvocations));
pipeline.Remove(typeof(InjectCallableConversions));
pipeline.Remove(typeof(StricterErrorChecking));
pipeline.Remove(typeof(RemoveDeadCode));
pipeline.Remove(typeof(OptimizeIterationStatements));
//pipeline.Remove(typeof(ProcessGenerators));
//pipeline.Remove(typeof(NormalizeIterationStatements));
pipeline.Remove(typeof(ProcessGenerators));
pipeline.Remove(typeof(NormalizeIterationStatements));
var adjustedPipeline = UnityScriptCompiler.Pipelines.AdjustBooPipeline(pipeline);
_compiler.Parameters.Pipeline = adjustedPipeline;
@ -437,6 +441,24 @@ namespace UnityScript2CSharp
node.Body.Accept(this);
}
public override bool EnterBlock(Block node)
{
var ret = base.EnterBlock(node);
var parentMedhod = node.ParentNode as Method;
if (parentMedhod == null)
return ret;
foreach (var local in parentMedhod.Locals)
{
var internalLocal = local.Entity as InternalLocal;
if (internalLocal != null)
internalLocal.OriginalDeclaration.ParentNode.Accept(this);
}
return ret;
}
public override void OnConstructor(Constructor node)
{
System.Console.WriteLine("Node type not supported yet : {0}\n\t{1}\n\t{2}", node.GetType().Name, node.ToString(), node.ParentNode.ToString());
@ -462,10 +484,22 @@ namespace UnityScript2CSharp
base.OnGenericParameterDeclaration(node);
}
public override void OnDeclarationStatement(DeclarationStatement node)
{
node.Declaration.Accept(this);
_builderAppend(" ");
_builderAppend(node.Declaration.Name);
if (node.Initializer != null)
{
_builderAppend(" = ");
node.Initializer.Accept(this);
}
}
public override void OnDeclaration(Declaration node)
{
System.Console.WriteLine("Node type not supported yet : {0}\n\t{1}\n\t{2}", node.GetType().Name, node.ToString(), node.ParentNode.ToString());
base.OnDeclaration(node);
_builderAppendIdented($" {F(node.Type.Entity)}");
}
public override void OnAttribute(Attribute node)
@ -508,12 +542,6 @@ namespace UnityScript2CSharp
_builderAppend(_newLine);
}
public override void OnDeclarationStatement(DeclarationStatement node)
{
System.Console.WriteLine("Node type not supported yet : {0}\n\t{1}\n\t{2}", node.GetType().Name, node.ToString(), node.ParentNode.ToString());
base.OnDeclarationStatement(node);
}
public override void OnMacroStatement(MacroStatement node)
{
System.Console.WriteLine("Node type not supported yet : {0}\n\t{1}\n\t{2}", node.GetType().Name, node.ToString(), node.ParentNode.ToString());
@ -540,7 +568,10 @@ namespace UnityScript2CSharp
node.TrueBlock.Accept(this);
if (node.FalseBlock != null)
{
_builderAppendIdented("else");
node.FalseBlock.Accept(this);
}
}
public override void OnUnlessStatement(UnlessStatement node)
@ -618,6 +649,9 @@ namespace UnityScript2CSharp
public override void OnMethodInvocationExpression(MethodInvocationExpression node)
{
if (node.Target.Entity.EntityType == EntityType.BuiltinFunction)
return;
node.Target.Accept(this);
_builderAppend('(');
foreach (var argument in node.Arguments)
@ -635,8 +669,12 @@ namespace UnityScript2CSharp
public override void OnBinaryExpression(BinaryExpression node)
{
System.Console.WriteLine("Node type not supported yet : {0}\n\t{1}\n\t{2}", node.GetType().Name, node.ToString(), node.ParentNode.ToString());
base.OnBinaryExpression(node);
if (node.IsSynthetic)
return;
node.Left.Accept(this);
_builderAppend($" {CSharpOperatorFor(node.Operator)} ");
node.Right.Accept(this);
}
public override void OnConditionalExpression(ConditionalExpression node)
@ -699,8 +737,7 @@ namespace UnityScript2CSharp
public override void OnNullLiteralExpression(NullLiteralExpression node)
{
System.Console.WriteLine("Node type not supported yet : {0}\n\t{1}\n\t{2}", node.GetType().Name, node.ToString(), node.ParentNode.ToString());
base.OnNullLiteralExpression(node);
_builderAppend("null");
}
public override void OnSelfLiteralExpression(SelfLiteralExpression node)
@ -855,6 +892,51 @@ namespace UnityScript2CSharp
private string CurrentIdentation { get; set; }
private string F(IEntity entity)
{
string typeName = null;
var externalType = entity as ExternalType;
if (externalType != null)
{
switch (externalType.ActualType.FullName)
{
case "System.String":
typeName = "string";
break;
case "System.Boolean":
typeName = "bool";
break;
case "System.Object":
typeName = "object";
break;
case "System.Int32":
typeName = "int";
break;
case "System.Int64":
typeName = "long";
break;
}
if (typeName == null && _usings.Contains(externalType.ActualType.Namespace))
{
typeName = externalType.Name;
}
}
return typeName ?? entity.Name;
}
public string CSharpOperatorFor(BinaryOperatorType op)
{
return (op != BinaryOperatorType.And) ? ((op != BinaryOperatorType.Or) ? BooPrinterVisitor.GetBinaryOperatorText(op) : "||") : "&&";
}
private static string ModifiersToString(TypeMemberModifiers modifiers)
{
return modifiers.ToString().ToLower().Replace(",", "");

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

@ -33,16 +33,34 @@
</PropertyGroup>
<ItemGroup>
<Reference Include="Boo.Lang">
<HintPath>..\..\..\..\External\Mono\builds\monodistribution\lib\mono\2.0\Boo.Lang.dll</HintPath>
<HintPath>Libs\Boo.Lang.dll</HintPath>
</Reference>
<Reference Include="Boo.Lang.Compiler">
<HintPath>..\..\..\..\External\Mono\builds\monodistribution\lib\mono\2.0\Boo.Lang.Compiler.dll</HintPath>
<HintPath>Libs\Boo.Lang.Compiler.dll</HintPath>
</Reference>
<Reference Include="Boo.Lang.Extensions">
<HintPath>..\..\..\..\External\Mono\builds\monodistribution\lib\mono\2.0\Boo.Lang.Extensions.dll</HintPath>
<HintPath>Libs\Boo.Lang.Extensions.dll</HintPath>
</Reference>
<Reference Include="Boo.Lang.Parser">
<HintPath>..\..\..\..\External\Mono\builds\monodistribution\lib\mono\2.0\Boo.Lang.Parser.dll</HintPath>
<HintPath>Libs\Boo.Lang.Parser.dll</HintPath>
</Reference>
<Reference Include="Boo.Lang.PatternMatching">
<HintPath>Libs\Boo.Lang.PatternMatching.dll</HintPath>
</Reference>
<Reference Include="Boo.Lang.Useful">
<HintPath>Libs\Boo.Lang.Useful.dll</HintPath>
</Reference>
<Reference Include="Mono.Cecil, Version=0.9.6.0, Culture=neutral, PublicKeyToken=0738eb9f132ed756, processorArchitecture=MSIL">
<HintPath>..\packages\Mono.Cecil.0.9.6.4\lib\net45\Mono.Cecil.dll</HintPath>
</Reference>
<Reference Include="Mono.Cecil.Mdb, Version=0.9.6.0, Culture=neutral, PublicKeyToken=0738eb9f132ed756, processorArchitecture=MSIL">
<HintPath>..\packages\Mono.Cecil.0.9.6.4\lib\net45\Mono.Cecil.Mdb.dll</HintPath>
</Reference>
<Reference Include="Mono.Cecil.Pdb, Version=0.9.6.0, Culture=neutral, PublicKeyToken=0738eb9f132ed756, processorArchitecture=MSIL">
<HintPath>..\packages\Mono.Cecil.0.9.6.4\lib\net45\Mono.Cecil.Pdb.dll</HintPath>
</Reference>
<Reference Include="Mono.Cecil.Rocks, Version=0.9.6.0, Culture=neutral, PublicKeyToken=0738eb9f132ed756, processorArchitecture=MSIL">
<HintPath>..\packages\Mono.Cecil.0.9.6.4\lib\net45\Mono.Cecil.Rocks.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Core" />
@ -52,23 +70,11 @@
<Reference Include="System.Data" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Xml" />
<Reference Include="Unity.Cecil">
<HintPath>..\..\..\..\External\Unity.Cecil\builds\lib\net40\Unity.Cecil.dll</HintPath>
</Reference>
<Reference Include="Unity.Cecil.Mdb">
<HintPath>..\..\..\..\External\Unity.Cecil\builds\lib\net40\Unity.Cecil.Mdb.dll</HintPath>
</Reference>
<Reference Include="Unity.Cecil.Pdb">
<HintPath>..\..\..\..\External\Unity.Cecil\builds\lib\net40\Unity.Cecil.Pdb.dll</HintPath>
</Reference>
<Reference Include="Unity.Cecil.Rocks">
<HintPath>..\..\..\..\External\Unity.Cecil\builds\lib\net40\Unity.Cecil.Rocks.dll</HintPath>
</Reference>
<Reference Include="UnityScript">
<HintPath>..\..\..\..\External\Mono\builds\monodistribution\lib\mono\2.0\UnityScript.dll</HintPath>
<HintPath>Libs\UnityScript.dll</HintPath>
</Reference>
<Reference Include="UnityScript.Lang">
<HintPath>..\..\..\..\External\Mono\builds\monodistribution\lib\mono\2.0\UnityScript.Lang.dll</HintPath>
<HintPath>Libs\UnityScript.Lang.dll</HintPath>
</Reference>
</ItemGroup>
<ItemGroup>
@ -77,6 +83,7 @@
</ItemGroup>
<ItemGroup>
<None Include="App.config" />
<None Include="packages.config" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>

112
readme.md Normal file
Просмотреть файл

@ -0,0 +1,112 @@
### What is this
Link to blog post.
### How to use
First, download the tool from [here](https://drive.google.com/open?id=0B7GZ512tQYxkM3RZUnQ0ZlVqWjQ) (you can also check the code in the branch scripting/drop-us-support). (latest version is 1.0.6416.19059)
Before running the conversion tool it is recommend:
1. Keep in mind that you'll have best results (i.e, a smoother conversion process) if your UnityScripts have *#pragma strict* applied to them.
2. Backup your project
3. Launch Unity editor and make sure you allow APIUpdater to run and update any obsolete API usages. This is necessary to avoid compilation errors during the conversion.
Next step is to run the application (UnityScript2CSharp.exe) passing the path to the project (**-p**) the Unity root installation folder (**-u**) and any additional assembly references (**-r**) used by the UnityScript scripts. Bellow you can find a list of valid command line arguments and their meaning:
| Argument | Meaning |
|----------------|-----------------------------------|
| -u, --unityPath | Required. Unity installation path. |
| -p, --projectPath | Required. Path of project to be converted. |
| -r, --references | Assembly references required by the scripts (space separated list).|
| -g, --gameassemblies | References previously built game assemblies (Assembly-*-firstpass.dll under Library/).|
| -s, –symbols | A (comma separated) list of custom symbols to be defined.|
| -o, –deleteOriginals | Deletes original files (default is to rename to .js.old)|
| -d | Dumps out the list of scripts being processed|
|-i | Ignore compilation errors. This allows the conversion process to continue instead of aborting. |
|-v, –verbose | Show verbose messages |
|-n, –dry-run | Run the conversion but do not change/create any files on disk. |
|–help | Display this help screen. |
**Example:**
UnityScript2CSharp.exe **-p** m:\Work\Repo\4-0_AngryBots **-u** M:\Work\Repo\unity\build **-r** "m:\AngryBot Assemblies\Assembly-CSharp.dll" "m:\AngryBot Assemblies\Assembly-UnityScript.dll" **-s** UNITY_ANDROID,UNITY_EDITOR
### Limitations
* Comments are not preserved
* *Guarded code* (#if … )
* UnityScript parser simply ignores guarded code when the condition evaluates to false leaving no traces of the original code when we are visiting the generated AST. The alternative for now is to run the tool multiple times in order to make sure all guarded code will eventually be processed. Each time the tool is executed user is required to merge the generated code manually.
* Formatting is not preserved
* UnityScript.Lang.Array (a.k.a *Array*) methods are not fully supported. We convert such type to *object[]* (this means that if your scripts relies on such methods we'll need to replace the variable declarations / instantiation with some other type (like *List<T>*, *Stack<T>*, etc) and adapt the code.
* Type inference in *anonymous function declarations* are inaccurate in some scenarios and may infer the wrong parameter / return type.
* Local variable scope sometimes gets messed up due to the way UnityScript scope works.
* Types with hyphens in the name (like *This-Is-Invalid*) are converted as *as-it-is* but they are not valid in C#
* Missing return values are not inject automatically (i.e, on a *non void* method, a *return;* statement will cause a compilation error in the converted code)
* Automatic conversion from **object** to *int/long/float/bool* etc is not supported (limited support for *int* -> *bool* conversion in conditional expressions is in place though).
* *for( init; condition; increment)* are converted to ***while***
* Methods **with same name as the declaring class** (invalid in C#) are converted *as-it-is*
* Invalid operands to **as** operators (which would always yield **null** in US) generates errors in C#
* Equality comparison against *null* used as **statement expressions** generate errors in C# (eg: *foo == null;*) (this code in meaningless, but harmless in US)
* Changing *foreach* loop variable is not supported
* Not supported features
* Property / Event definition
* Macros
* Literals
* Regular expressions
* Exception handling
Note that any unsupported language construct (a.k.a, AST node type), will inject a comment in the converted source including the piece of code that is not supported and related source/line information.
### How to build
### How to run tests
### FAQ
>#### **Q**: During conversion, the following error is shown in the console:
"*Conversion aborted due to compilation errors:*"
>
> And then some compiler errors complaining about types not being valid.
>#### **A**: You are missing some assembly reference; if the type in question is define in the project scripts it is most likely Assembly-CSharp.dll or Assembly-UnityScript.dll (just run the conversion tool again passing **-r** *path_to_assembly_csharp path_to_assembly_unityscript* as an argument.
----
>#### **Q**: Some of my UnityScript code is not included in the converted CSharp
>#### **A**: Most likely this is code *guarded* by *SYMBOLS*. Look for **#if ** / **#else** directives in the original UnityScript and run the conversion tool passing the right symbols. Note that in some cases one or more symbols may introduce mutually exclusive source snippets which means that no matter if you specify the symbol or not, necessarily some region of the code will be excluded, as in the example:
>
>**#if !SYMBOL_1**
> // Snippet 1
>**#endif**
>
**#if SYMBOL_1**
// Snippet 2
**#endif**
>In the example above, if you run the conversion tool specifying the symbol *SYMBOL_1* , **Snippet 1** will be skipped (because it is guarded by a **!SYMBOL_1**) and **Snippet 2** will be included. If you don't, **Snippet 1** will be included but **Snippet 2** will not (because *SYMBOL_1* is not defined).
>The best way to workaround this limitation is to set-up a local VCS repository (git, mercurial or any other of your option) and run the conversion tool with a set of *symbols* then commit the generated code, revert the changes to the UnityScript scripts (i.e, restore the original scripts), run the conversion tool again with a different set of *Symbols* and merge the new version of the converted scripts.
----