///
/// Copyright © 2003-2008 JetBrains s.r.o.
/// You may distribute under the terms of the GNU General Public License, as published by the Free Software Foundation, version 2 (see License.txt in the repository root folder).
///
using System;
using System.Collections;
using System.Globalization;
using System.Reflection;
using System.Text;
using Microsoft.Build.Framework;
using Microsoft.Build.Tasks;
using Microsoft.Build.Utilities;
namespace JetBrains.Build
{
///
/// An MSBuild task that compiles the IL projects.
///
public class JScript : ManagedCompiler
{
#region Init
public JScript()
{
HostCompilerSupportsAllParameters = false;
NoConfig = false;
}
#endregion
#region Attributes
///
/// Automatically reference assemblies based on imported namespaces and fully-qualified names (on by default).
///
public bool Autoref
{
get
{
return (bool)Bag["Autoref"];
}
set
{
Bag["Autoref"] = value;
}
}
///
/// Disable language features to allow better code generation.
///
public bool Fast
{
get
{
return (bool)Bag["Fast"];
}
set
{
Bag["Fast"] = value;
}
}
///
/// Do not import standard library (mscorlib.dll) and change autoref default to off.
///
public string NoStandardLib
{
get
{
return (string)base.Bag["NoStandardLib"];
}
set
{
base.Bag["NoStandardLib"] = value;
}
}
///
/// Limit which platforms this code can run on; must be x86, Itanium, x64, or anycpu, which is the default.
///
public string Platform
{
get
{
return (string)base.Bag["Platform"];
}
set
{
base.Bag["Platform"] = value;
}
}
///
/// Set warning level (0-4).
///
public int WarningLevel
{
get
{
return (int)Bag["WarningLevel"];
}
set
{
Bag["WarningLevel"] = value;
}
}
#endregion
#region Implementation
internal static void CommandLine_AppendSwitchAliased(CommandLineBuilderExtension commandLine, string switchName, string alias, string parameter)
{
commandLine.AppendSwitchIfNotNull(switchName, alias + "=");
commandLine.GetType().InvokeMember("AppendTextWithQuoting", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.InvokeMethod, null, commandLine, new object[] {parameter});
}
private static void CommandLine_AppendPlusOrMinusSwitch(string sSwitchName, Hashtable bag, string sBagPropertyName, CommandLineBuilderExtension commandLine)
{
commandLine.GetType().InvokeMember("AppendPlusOrMinusSwitch", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.InvokeMethod, null, commandLine, new object[] {sSwitchName, bag, sBagPropertyName});
}
private static void CommandLine_AppendSwitchWithInteger(string sSwitchName, Hashtable bag, string sBagPropertyName, CommandLineBuilderExtension commandLine)
{
commandLine.GetType().InvokeMember("AppendSwitchWithInteger", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.InvokeMethod, null, commandLine, new object[] {sSwitchName, bag, sBagPropertyName});
}
private static bool IsLegalIdentifier(string identifier)
{
if(identifier.Length == 0)
return false;
if(!TokenChar.IsLetter(identifier[0]) && (identifier[0] != '_'))
return false;
for(int i = 1; i < identifier.Length; i++)
{
char c = identifier[i];
if(((!TokenChar.IsLetter(c) && !TokenChar.IsDecimalDigit(c)) && (!TokenChar.IsConnecting(c) && !TokenChar.IsCombining(c))) && !TokenChar.IsFormatting(c))
return false;
}
return true;
}
///
/// Adds JScript-specific command-line commands not handled by the base class.
///
/// The command line to popuplate.
protected void AddMoreCommandLineCommands(CommandLineBuilderExtension commandLine)
{
AddMoreCommandLineCommands_TargetType(commandLine);
}
///
/// The target type command line commands.
///
/// The command line to popuplate.
protected void AddMoreCommandLineCommands_TargetType(CommandLineBuilderExtension commandLine)
{
CommandLineAppendWhenTrue(commandLine, "/DLL", "Dll");
CommandLineAppendWhenTrue(commandLine, "/EXE", "Exe");
}
///
/// Carries out an internal CommandLineBuilderExtension.AppendWhenTrue method.
///
protected void CommandLineAppendWhenTrue(CommandLineBuilderExtension commandLine, string switchName, string parameterName)
{
object o = Bag[parameterName];
if((o != null) && ((bool)o))
commandLine.AppendSwitch(switchName);
}
internal string GetDefineConstantsSwitch(string originalDefineConstants)
{
if(originalDefineConstants != null)
{
var builder = new StringBuilder();
foreach(string str in originalDefineConstants.Split(new[] {',', ';', ' '}))
{
if(IsLegalIdentifier(str))
{
if(builder.Length > 0)
builder.Append(";");
builder.Append(str);
}
else if(str.Length > 0)
Log.LogWarning("Invalid define parameter “{0}”.", str);
}
if(builder.Length > 0)
return builder.ToString();
}
return null;
}
///
/// Taken form the CSC compiler.
///
private void AddReferencesToCommandLine(CommandLineBuilderExtension commandLine)
{
if((base.References != null) && (base.References.Length != 0))
{
foreach(ITaskItem item in base.References)
{
string metadata = item.GetMetadata("Aliases");
if((metadata == null) || (metadata.Length == 0))
commandLine.AppendSwitchIfNotNull("/reference:", item.ItemSpec);
else
{
foreach(string str2 in metadata.Split(new[] {','}))
{
string str3 = str2.Trim();
if(str2.Length != 0)
{
if(str3.IndexOfAny(new[] {',', ' ', ';', '"'}) != -1)
throw new InvalidOperationException(string.Format("The assembly “{0}” alias “{1}” contains invalid characters.", item.ItemSpec, str3));
if(string.Compare("global", str3, StringComparison.OrdinalIgnoreCase) == 0)
commandLine.AppendSwitchIfNotNull("/reference:", item.ItemSpec);
else
CommandLine_AppendSwitchAliased(commandLine, "/reference:", str3, item.ItemSpec);
}
}
}
}
}
}
#endregion
#region Overrides
///
///Fills the specified with the switches and other information that can go into a response file.
///
///
///The to fill with switches and other information.
protected override void AddResponseFileCommands(CommandLineBuilderExtension commandLine)
{
commandLine.AppendSwitchIfNotNull("/platform:", Platform);
CommandLine_AppendPlusOrMinusSwitch("/fast", Bag, "Fast", commandLine);
CommandLine_AppendPlusOrMinusSwitch("/autoref", Bag, "Autoref", commandLine);
commandLine.AppendSwitchIfNotNull("/lib:", AdditionalLibPaths, ",");
commandLine.AppendSwitchIfNotNull("/win32res:", Win32Resource);
CommandLine_AppendPlusOrMinusSwitch("/warnaserror", Bag, "TreatWarningsAsErrors", commandLine);
CommandLine_AppendSwitchWithInteger("/warn:", Bag, "WarningLevel", commandLine);
CommandLine_AppendPlusOrMinusSwitch("/nostdlib", Bag, "NoStandardLib", commandLine);
commandLine.AppendSwitchUnquotedIfNotNull("/define:", GetDefineConstantsSwitch(DefineConstants));
AddReferencesToCommandLine(commandLine);
base.AddResponseFileCommands(commandLine);
if(ResponseFiles != null)
{
foreach(ITaskItem item in ResponseFiles)
commandLine.AppendSwitchIfNotNull("@", item.ItemSpec);
}
}
///
///Returns the fully qualified path to the executable file.
///
///
///
///The fully qualified path to the executable file.
///
///
protected override string GenerateFullPathToTool()
{
string path = ToolLocationHelper.GetPathToDotNetFrameworkFile(ToolName, TargetDotNetFrameworkVersion.VersionLatest);
if(path == null)
Log.LogError("Could not locate the {0} compiler.", ToolName);
return path;
}
///
///Gets the name of the executable file to run.
///
///
///
///The name of the executable file to run.
///
///
protected override string ToolName
{
get
{
return "jsc.exe";
}
}
#endregion
#region TokenChar Type
internal static class TokenChar
{
// Methods
#region Implementation
internal static bool IsCombining(char c)
{
UnicodeCategory unicodeCategory = char.GetUnicodeCategory(c);
if((unicodeCategory != UnicodeCategory.NonSpacingMark) && (unicodeCategory != UnicodeCategory.SpacingCombiningMark))
return false;
return true;
}
internal static bool IsConnecting(char c)
{
return (char.GetUnicodeCategory(c) == UnicodeCategory.ConnectorPunctuation);
}
internal static bool IsDecimalDigit(char c)
{
return (char.GetUnicodeCategory(c) == UnicodeCategory.DecimalDigitNumber);
}
internal static bool IsFormatting(char c)
{
return (char.GetUnicodeCategory(c) == UnicodeCategory.Format);
}
internal static bool IsHexDigit(char c)
{
if((((c < '0') || (c > '9')) && ((c < 'A') || (c > 'F'))) && ((c < 'a') || (c > 'f')))
return false;
return true;
}
internal static bool IsLetter(char c)
{
UnicodeCategory unicodeCategory = char.GetUnicodeCategory(c);
if((((unicodeCategory != UnicodeCategory.UppercaseLetter) && (unicodeCategory != UnicodeCategory.LowercaseLetter)) && ((unicodeCategory != UnicodeCategory.TitlecaseLetter) && (unicodeCategory != UnicodeCategory.ModifierLetter))) && ((unicodeCategory != UnicodeCategory.OtherLetter) && (unicodeCategory != UnicodeCategory.LetterNumber)))
return false;
return true;
}
internal static bool IsNewLine(char c)
{
if(((c != '\r') && (c != '\n')) && (c != '\u2028'))
return (c == '\u2029');
return true;
}
internal static bool IsOctalDigit(char c)
{
return ((c >= '0') && (c <= '7'));
}
#endregion
}
#endregion
}
}