using System.CodeDom;
using System.CodeDom.Compiler;
using System.Collections;
+using System.Collections.Specialized;
using System.Reflection;
using System.Text;
using System.Web.UI;
#if NET_2_0
bool isRebuilding = false;
protected Hashtable partialNameOverride = new Hashtable();
+ protected CodeTypeDeclaration partialClass;
+ protected CodeTypeReferenceExpression partialClassExpr;
#endif
protected CodeTypeDeclaration mainClass;
protected CodeTypeReferenceExpression mainClassExpr;
protected BaseCompiler (TemplateParser parser)
{
- compilerParameters = new CompilerParameters ();
this.parser = parser;
}
+ internal CodeStatement AddLinePragma (CodeExpression expression, ControlBuilder builder)
+ {
+ return AddLinePragma (new CodeExpressionStatement (expression), builder);
+ }
+
+ internal CodeStatement AddLinePragma (CodeStatement statement, ControlBuilder builder)
+ {
+ if (builder == null || statement == null)
+ return statement;
+
+ ILocation location = null;
+
+ if (!(builder is CodeRenderBuilder))
+ location = builder.location;
+
+ if (location != null)
+ return AddLinePragma (statement, location);
+ else
+ return AddLinePragma (statement, builder.line, builder.fileName);
+ }
+
+ internal CodeStatement AddLinePragma (CodeStatement statement, ILocation location)
+ {
+ if (location == null || statement == null)
+ return statement;
+
+ return AddLinePragma (statement, location.BeginLine, location.Filename);
+ }
+
+ internal CodeStatement AddLinePragma (CodeStatement statement, int line, string fileName)
+ {
+ if (statement == null)
+ return null;
+
+ statement.LinePragma = new CodeLinePragma (fileName, line);
+ return statement;
+ }
+
+ internal CodeTypeMember AddLinePragma (CodeTypeMember member, ControlBuilder builder)
+ {
+ if (builder == null || member == null)
+ return member;
+
+ ILocation location = builder.location;
+
+ if (location != null)
+ return AddLinePragma (member, location);
+ else
+ return AddLinePragma (member, builder.line, builder.fileName);
+ }
+
+ internal CodeTypeMember AddLinePragma (CodeTypeMember member, ILocation location)
+ {
+ if (location == null || member == null)
+ return member;
+
+ return AddLinePragma (member, location.BeginLine, location.Filename);
+ }
+
+ internal CodeTypeMember AddLinePragma (CodeTypeMember member, int line, string fileName)
+ {
+ if (member == null)
+ return null;
+
+ member.LinePragma = new CodeLinePragma (fileName, line);
+ return member;
+ }
+
void Init ()
{
unit = new CodeCompileUnit ();
#if NET_2_0
if (parser.IsPartial) {
- string ns = null;
- string classtype = parser.PartialClassName;
+ string partialns = null;
+ string partialclasstype = parser.PartialClassName;
- if (classtype.Contains (".")) {
- int dot = classtype.LastIndexOf (".");
- ns = classtype.Substring (0, dot);
- classtype = classtype.Substring (dot + 1);
+ int partialdot = partialclasstype.LastIndexOf ('.');
+ if (partialdot != -1) {
+ partialns = partialclasstype.Substring (0, partialdot);
+ partialclasstype = partialclasstype.Substring (partialdot + 1);
}
- mainNS = new CodeNamespace (ns);
- mainClass = new CodeTypeDeclaration (classtype);
- mainClass.IsPartial = true;
- mainClassExpr = new CodeTypeReferenceExpression (parser.PartialClassName);
- } else {
+ CodeNamespace partialNS = new CodeNamespace (partialns);
+ partialClass = new CodeTypeDeclaration (partialclasstype);
+ partialClass.IsPartial = true;
+ partialClassExpr = new CodeTypeReferenceExpression (parser.PartialClassName);
+
+ unit.Namespaces.Add (partialNS);
+ partialClass.TypeAttributes = TypeAttributes.Public;
+ partialNS.Types.Add (partialClass);
+ }
+#endif
+
+ string mainclasstype = parser.ClassName;
+ string mainns = "ASP";
+
+#if NET_2_0
+ int maindot = mainclasstype.LastIndexOf ('.');
+ if (maindot != -1) {
+ mainns = mainclasstype.Substring (0, maindot);
+ mainclasstype = mainclasstype.Substring (maindot + 1);
+ }
#endif
- mainNS = new CodeNamespace ("ASP");
- mainClass = new CodeTypeDeclaration (parser.ClassName);
- mainClass.BaseTypes.Add (new CodeTypeReference (parser.BaseType.FullName));
- mainClassExpr = new CodeTypeReferenceExpression ("ASP." + parser.ClassName);
+
+ mainNS = new CodeNamespace (mainns);
+ mainClass = new CodeTypeDeclaration (mainclasstype);
+ CodeTypeReference baseTypeRef;
#if NET_2_0
+ if (partialClass != null) {
+ baseTypeRef = new CodeTypeReference (parser.PartialClassName);
+ baseTypeRef.Options |= CodeTypeReferenceOptions.GlobalReference;
+ } else {
+ baseTypeRef = new CodeTypeReference (parser.BaseType.FullName);
+ if (parser.BaseTypeIsGlobal)
+ baseTypeRef.Options |= CodeTypeReferenceOptions.GlobalReference;
}
+#else
+ baseTypeRef = new CodeTypeReference (parser.BaseType.FullName);
#endif
+ mainClass.BaseTypes.Add (baseTypeRef);
+
+ mainClassExpr = new CodeTypeReferenceExpression (mainns + "." + mainclasstype);
+
unit.Namespaces.Add (mainNS);
mainClass.TypeAttributes = TypeAttributes.Public;
mainNS.Types.Add (mainClass);
mainNS.Imports.Add (new CodeNamespaceImport ((string) o));
}
+ // StringCollection.Contains has O(n) complexity, but
+ // considering the number of comparisons we make on
+ // average and the fact that using an intermediate array
+ // would be even more costly, this is fine here.
+ StringCollection refAsm = unit.ReferencedAssemblies;
+ string asmName;
if (parser.Assemblies != null) {
foreach (object o in parser.Assemblies) {
- if (o is string)
- unit.ReferencedAssemblies.Add ((string) o);
+ asmName = o as string;
+ if (asmName != null && !refAsm.Contains (asmName))
+ refAsm.Add (asmName);
}
}
+#if NET_2_0
+ ArrayList al = WebConfigurationManager.ExtraAssemblies;
+ if (al != null && al.Count > 0) {
+ foreach (object o in al) {
+ asmName = o as string;
+ if (asmName != null && !refAsm.Contains (asmName))
+ refAsm.Add (asmName);
+ }
+ }
+
+ IList list = BuildManager.CodeAssemblies;
+ if (list != null && list.Count > 0) {
+ Assembly asm;
+ foreach (object o in list) {
+ asm = o as Assembly;
+ if (o == null)
+ continue;
+ asmName = asm.Location;
+ if (asmName != null && !refAsm.Contains (asmName))
+ refAsm.Add (asmName);
+ }
+ }
+#endif
// Late-bound generators specifics (as for MonoBASIC/VB.NET)
unit.UserData["RequireVariableDeclaration"] = parser.ExplicitOn;
unit.UserData["AllowLateBound"] = !parser.StrictOn;
CreateConstructor (null, null);
}
-#if NET_2_0
- internal CodeDomProvider Provider {
- get { return provider; }
- }
+ internal CodeFieldReferenceExpression GetMainClassFieldReferenceExpression (string fieldName)
+ {
+ CodeTypeReference mainClassTypeRef;
+ mainClassTypeRef = new CodeTypeReference (mainNS.Name + "." + mainClass.Name);
- internal CodeCompileUnit CompileUnit {
- get { return unit; }
- }
+#if NET_2_0
+ mainClassTypeRef.Options |= CodeTypeReferenceOptions.GlobalReference;
#endif
+ return new CodeFieldReferenceExpression (
+ new CodeTypeReferenceExpression (mainClassTypeRef), fieldName);
+ }
+
protected virtual void CreateStaticFields ()
{
CodeMemberField fld = new CodeMemberField (typeof (bool), "__initialized");
mainClass.Members.Add (fld);
}
+#if NET_2_0
+ void AssignAppRelativeVirtualPath (CodeConstructor ctor)
+ {
+ Type baseType = parser.CodeFileBaseClassType;
+
+ if (baseType == null)
+ baseType = parser.BaseType;
+ if (baseType == null)
+ return;
+ if (!baseType.IsSubclassOf (typeof (System.Web.UI.TemplateControl)))
+ return;
+
+ string arvp = Path.Combine (parser.BaseVirtualDir, Path.GetFileName (parser.InputFile));
+ if (VirtualPathUtility.IsAbsolute (arvp))
+ arvp = "~" + arvp;
+
+ CodeTypeReference baseTypeRef = new CodeTypeReference (baseType.FullName);
+ if (parser.BaseTypeIsGlobal)
+ baseTypeRef.Options |= CodeTypeReferenceOptions.GlobalReference;
+
+ CodeExpression cast = new CodeCastExpression (baseTypeRef, new CodeThisReferenceExpression ());
+ CodePropertyReferenceExpression arvpProp = new CodePropertyReferenceExpression (cast, "AppRelativeVirtualPath");
+ CodeAssignStatement arvpAssign = new CodeAssignStatement ();
+ arvpAssign.Left = arvpProp;
+ arvpAssign.Right = new CodePrimitiveExpression (VirtualPathUtility.RemoveTrailingSlash (arvp));
+ ctor.Statements.Add (arvpAssign);
+ }
+#endif
+
protected virtual void CreateConstructor (CodeStatementCollection localVars,
CodeStatementCollection trueStmt)
{
if (localVars != null)
ctor.Statements.AddRange (localVars);
- CodeTypeReferenceExpression r;
#if NET_2_0
- if (parser.IsPartial)
- r = new CodeTypeReferenceExpression (mainClass.Name);
- else
+ AssignAppRelativeVirtualPath (ctor);
#endif
- r = new CodeTypeReferenceExpression (mainNS.Name + "." + mainClass.Name);
- CodeFieldReferenceExpression initialized;
- initialized = new CodeFieldReferenceExpression (r, "__initialized");
+
+ CodeFieldReferenceExpression initialized = GetMainClassFieldReferenceExpression ("__initialized");
CodeBinaryOperatorExpression bin;
bin = new CodeBinaryOperatorExpression (initialized,
CodeAssignStatement assign = new CodeAssignStatement (initialized,
new CodePrimitiveExpression (true));
- CodeConditionStatement cond = new CodeConditionStatement (bin, assign);
+ CodeConditionStatement cond = new CodeConditionStatement ();
+ cond.Condition = bin;
+
if (trueStmt != null)
cond.TrueStatements.AddRange (trueStmt);
+ cond.TrueStatements.Add (assign);
ctor.Statements.Add (cond);
}
if (parser.Scripts == null || parser.Scripts.Count == 0)
return;
+ ServerSideScript sss;
+
foreach (object o in parser.Scripts) {
- if (o is string)
- mainClass.Members.Add (new CodeSnippetTypeMember ((string) o));
+ sss = o as ServerSideScript;
+
+ if (sss == null)
+ continue;
+
+ mainClass.Members.Add (AddLinePragma (new CodeSnippetTypeMember (sss.Script), sss.Location));
}
}
{
}
+#if NET_2_0
+ void InternalCreatePageProperty (string retType, string name, string contextProperty)
+ {
+ CodeMemberProperty property = new CodeMemberProperty ();
+ property.Name = name;
+ property.Type = new CodeTypeReference (retType);
+ property.Attributes = MemberAttributes.Family | MemberAttributes.Final;
+
+ CodeMethodReturnStatement ret = new CodeMethodReturnStatement ();
+ CodeCastExpression cast = new CodeCastExpression ();
+ ret.Expression = cast;
+
+ CodePropertyReferenceExpression refexp = new CodePropertyReferenceExpression ();
+ refexp.TargetObject = new CodePropertyReferenceExpression (new CodeThisReferenceExpression (), "Context");
+ refexp.PropertyName = contextProperty;
+
+ cast.TargetType = new CodeTypeReference (retType);
+ cast.Expression = refexp;
+
+ property.GetStatements.Add (ret);
+ if (partialClass == null)
+ mainClass.Members.Add (property);
+ else
+ partialClass.Members.Add (property);
+ }
+
+ protected void CreateProfileProperty ()
+ {
+ string retType;
+ if (AppCodeCompiler.HaveCustomProfile (WebConfigurationManager.GetSection ("system.web/profile") as ProfileSection))
+ retType = "ProfileCommon";
+ else
+ retType = "System.Web.Profile.DefaultProfile";
+ InternalCreatePageProperty (retType, "Profile", "Profile");
+ }
+#endif
+
protected virtual void AddInterfaces ()
{
if (parser.Interfaces == null)
if (results.NativeCompilerReturnValue == 0)
return;
- StringWriter writer = new StringWriter();
- provider.CreateGenerator().GenerateCodeFromCompileUnit (unit, writer, null);
- throw new CompilationException (parser.InputFile, results.Errors, writer.ToString ());
+ string fileText = null;
+ CompilerErrorCollection errors = results.Errors;
+ CompilerError ce = (errors != null && errors.Count > 0) ? errors [0] : null;
+ string inFile = (ce != null) ? ce.FileName : null;
+
+ if (inFile != null && File.Exists (inFile)) {
+ using (StreamReader sr = File.OpenText (inFile)) {
+ fileText = sr.ReadToEnd ();
+ }
+ } else {
+ StringWriter writer = new StringWriter();
+ provider.CreateGenerator().GenerateCodeFromCompileUnit (unit, writer, null);
+ fileText = writer.ToString ();
+ }
+ throw new CompilationException (parser.InputFile, errors, fileText);
}
protected string DynamicDir ()
return AppDomain.CurrentDomain.SetupInformation.DynamicBase;
}
- [MonoTODO ("find out how to extract the warningLevel and compilerOptions in the <system.codedom> case")]
- public virtual Type GetCompiledType ()
+ internal static CodeDomProvider CreateProvider (string lang, out string compilerOptions, out int warningLevel, out string tempdir)
{
- Type type = CachingCompiler.GetTypeFromCache (parser.InputFile);
- if (type != null)
- return type;
-
- Init ();
- string lang = parser.Language;
+ return CreateProvider (HttpContext.Current, lang, out compilerOptions, out warningLevel, out tempdir);
+ }
+
+ internal static CodeDomProvider CreateProvider (HttpContext context, string lang, out string compilerOptions, out int warningLevel, out string tempdir)
+ {
+ CodeDomProvider ret = null;
+
#if NET_2_0
CompilationSection config = (CompilationSection) WebConfigurationManager.GetSection ("system.web/compilation");
Compiler comp = config.Compilers[lang];
-
- string compilerOptions = "";
- int warningLevel = 0;
-
+
if (comp == null) {
CompilerInfo info = CodeDomProvider.GetCompilerInfo (lang);
- if (info != null && info.IsCodeDomProviderTypeValid)
- provider = info.CreateProvider ();
-
- // XXX there's no way to get
- // warningLevel or compilerOptions out
- // of the provider.. they're in the
- // configuration section, though.
- }
- else {
- Type t = Type.GetType (comp.Type, true);
- provider = Activator.CreateInstance (t) as CodeDomProvider;
+ if (info != null && info.IsCodeDomProviderTypeValid) {
+ ret = info.CreateProvider ();
+
+ CompilerParameters cp = info.CreateDefaultCompilerParameters ();
+ compilerOptions = cp.CompilerOptions;
+ warningLevel = cp.WarningLevel;
+ } else {
+ compilerOptions = String.Empty;
+ warningLevel = 2;
+ }
+ } else {
+ Type t = HttpApplication.LoadType (comp.Type, true);
+ ret = Activator.CreateInstance (t) as CodeDomProvider;
compilerOptions = comp.CompilerOptions;
warningLevel = comp.WarningLevel;
}
-
#else
CompilationConfiguration config;
- config = CompilationConfiguration.GetInstance (parser.Context);
- provider = config.GetProvider (lang);
+ config = CompilationConfiguration.GetInstance (context);
+ ret = config.GetProvider (lang);
- string compilerOptions = config.GetCompilerOptions (lang);
- int warningLevel = config.GetWarningLevel (lang);
+ compilerOptions = config.GetCompilerOptions (lang);
+ warningLevel = config.GetWarningLevel (lang);
#endif
- if (provider == null)
+ tempdir = config.TempDirectory;
+
+ return ret;
+ }
+
+ [MonoTODO ("find out how to extract the warningLevel and compilerOptions in the <system.codedom> case")]
+ public virtual Type GetCompiledType ()
+ {
+ Type type = CachingCompiler.GetTypeFromCache (parser.InputFile);
+ if (type != null)
+ return type;
+
+ Init ();
+ string lang = parser.Language;
+ string tempdir;
+ string compilerOptions;
+ int warningLevel;
+
+ Provider = CreateProvider (parser.Context, lang, out compilerOptions, out warningLevel, out tempdir);
+ if (Provider == null)
throw new HttpException ("Configuration error. Language not supported: " +
lang, 500);
+#if !NET_2_0
compiler = provider.CreateCompiler ();
+#endif
- compilerParameters.IncludeDebugInformation = parser.Debug;
- compilerParameters.CompilerOptions = compilerOptions + " " + parser.CompilerOptions;
-
- compilerParameters.WarningLevel = warningLevel;
+ CompilerParameters parameters = CompilerParameters;
+ parameters.IncludeDebugInformation = parser.Debug;
+ parameters.CompilerOptions = compilerOptions + " " + parser.CompilerOptions;
+ parameters.WarningLevel = warningLevel;
+
bool keepFiles = (Environment.GetEnvironmentVariable ("MONO_ASPNET_NODELETE") != null);
- string tempdir = config.TempDirectory;
if (tempdir == null || tempdir == "")
tempdir = DynamicDir ();
TempFileCollection tempcoll = new TempFileCollection (tempdir, keepFiles);
- compilerParameters.TempFiles = tempcoll;
+ parameters.TempFiles = tempcoll;
string dllfilename = Path.GetFileName (tempcoll.AddExtension ("dll", true));
- compilerParameters.OutputAssembly = Path.Combine (DynamicDir (), dllfilename);
+ parameters.OutputAssembly = Path.Combine (DynamicDir (), dllfilename);
CompilerResults results = CachingCompiler.Compile (this);
CheckCompilerErrors (results);
Assembly assembly = results.CompiledAssembly;
if (assembly == null) {
- if (!File.Exists (compilerParameters.OutputAssembly)) {
+ if (!File.Exists (parameters.OutputAssembly)) {
results.TempFiles.Delete ();
throw new CompilationException (parser.InputFile, results.Errors,
"No assembly returned after compilation!?");
}
- assembly = Assembly.LoadFrom (compilerParameters.OutputAssembly);
+ assembly = Assembly.LoadFrom (parameters.OutputAssembly);
}
results.TempFiles.Delete ();
}
#endif
- internal CompilerParameters CompilerParameters {
- get { return compilerParameters; }
+ internal CodeDomProvider Provider {
+ get { return provider; }
+ set { provider = value; }
}
- internal CodeCompileUnit Unit {
- get { return unit; }
+ internal ICodeCompiler Compiler {
+ get { return compiler; }
+ set { compiler = value; }
+ }
+
+ internal CompilerParameters CompilerParameters {
+ get {
+ if (compilerParameters == null)
+ compilerParameters = new CompilerParameters ();
+
+ return compilerParameters;
+ }
+
+ set { compilerParameters = value; }
}
- internal virtual ICodeCompiler Compiler {
- get { return compiler; }
+ internal CodeCompileUnit CompileUnit {
+ get { return unit; }
}
internal TemplateParser Parser {