Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

A simple programming model for creating extensions/add-ins for the Mo…

…no C# compiler.

I need to be able to access the abstract representation of a C# program immediately after the parsing stage has succeeded but before
the type checker kicks in. More than just this, I need to be able to modify the types assigned to various program features such as
method parameters etc. This change implement a very simple extensibility model that provides me with the minimum functionality to
perform these types of actions. I expect that this programming model will grow and change considerably over time as I build by
compiler add-in out.

Since the compiler (dmcs.exe) now exposes a public extensibility API that is intended to be consumed by third-party add-ins, the
target assembly must now have a strong name in order that other signed assemblies can reference it. The project has been modified to
reference the standard "mono.pub" key file.

To create an add-in, simply implement the new Mono.CompilerServices.Extensibility.IAddIn interface. This provides entry points for
parsing additional command-line options as well as access to the abstract parse tree results. Your assembly will be picked up by
dmcs.exe from the GAC so make sure that you remember to give your add-in assembly a strong name. dmcs.exe uses its application
configuration file (dmcs.exe.config) to determine which add-ins to load. To configure dmcs.exe to use your add-in, modify the
configuration file to include an "add-ins" key which is a semicolon-separated list of assembly qualified type names referring to
classes implementing the IAddIn interface. Here is a sample configuration file:

<?xml version="1.0"?>
<configuration>
  <startup>
    <supportedRuntime version="v4.0.30319"/>
  </startup>
  <appSettings>
    <add key="add-ins" value="Mono.DuctileSharp.AddIn, Mono.DuctileSharp, Version=1.0.0.0, Culture=neutral,
PublicKeyToken=1b947822772207a0"/>
  </appSettings>
</configuration>

I'm sure that this loading mechanism will change over time too! Happy hacking!

Detailed code review:

.gitignore
  Added Mercurial common repository files to ignore list.

mcs/class/Mono.CSharp.csproj
mcs/mcs/dmcs.csproj
mcs/mcs/dmcs.exe.sources
mcs/mcs/gmcs.csproj
mcs/mcs/gmcs.exe.sources
mcs/mcs/smcs.exe.sources
  Added new extensibility support classes into various project files and file
  lists.

mcs/mcs/AssemblyInfo.cs
  Added strong name to dmcs.exe etc. by adding AssemblyDelaySign and
  AssemblyKeyFile attributes. This is necessary to allow other signed assemblies
  to reference dmcs.exe etc. which is necessary for third-party add-ins to
  access the new extensibility interfaces.

mcs/mcs/add_in_manager.cs
  New: manages compiler add-ins based on Mono.CompilerServices.Extensibility
  interfaces.

mcs/mcs/class.cs
  Implemented ITypeInfo on Mono.CSharp.Class.

mcs/mcs/driver.cs
  Added calls into AddInManager to load and invoke add-ins at start, during
  command-line argument parsing and immediately after parsing has completed
  but before type resolution is performed.

mcs/mcs/ecore.cs
  Implemented ITypeExpression on Mono.CSharp.FullNamedExpression.

mcs/mcs/extensibility/IAddIn.cs
  New: provides main entry points for a compiler add-in.

mcs/mcs/extensibility/ILocation.cs
  New: supplies source code location information.

mcs/mcs/extensibility/IMethodInfo.cs
  New: enables basic manipulation of methods.

mcs/mcs/extensibility/IParameterInfo.cs
  New: enables basic manipulation of parameters.

mcs/mcs/extensibility/ITypeExpression.cs
  New: enables basic manipulation of type expressions.

mcs/mcs/extensibility/ITypeExpressionFactory.cs
  New: allows add-ins to create type expressions.

mcs/mcs/extensibility/ITypeInfo.cs
  New: enables basic manipulation of types.

mcs/mcs/location.cs
  Implemented ILocation on Mono.CSharp.Location.

mcs/mcs/method.cs
  Implemented IMethodInfo on Mono.CSharp.Method.

mcs/mcs/parameter.cs
  Implemented IParameterInfo on Mono.CSharp.Parameter.
  • Loading branch information...
commit a0456c852e48f6822e6bdad7b4d12a357ade0d01 1 parent 0a49cf4
@rcook authored
View
3  .gitignore
@@ -35,3 +35,6 @@
/ltsugar.m4
/lt~obsolete.m4
/ltversion.m4
+/.hg
+/.hgignore
+
View
24 mcs/class/Mono.CSharp/Mono.CSharp.csproj
@@ -50,6 +50,9 @@
<Compile Include="..\..\class\Mono.CompilerServices.SymbolWriter\MonoSymbolWriter.cs">
<Link>MonoSymbolWriter.cs</Link>
</Compile>
+ <Compile Include="..\..\mcs\add_in_manager.cs">
+ <Link>add_in_manager.cs</Link>
+ </Compile>
<Compile Include="..\..\mcs\anonymous.cs">
<Link>anonymous.cs</Link>
</Compile>
@@ -119,6 +122,27 @@
<Compile Include="..\..\mcs\expression.cs">
<Link>expression.cs</Link>
</Compile>
+ <Compile Include="..\..\mcs\extensibility\IAddIn.cs">
+ <Link>extensibility\IAddIn.cs</Link>
+ </Compile>
+ <Compile Include="..\..\mcs\extensibility\ILocation.cs">
+ <Link>extensibility\ILocation.cs</Link>
+ </Compile>
+ <Compile Include="..\..\mcs\extensibility\IMethodInfo.cs">
+ <Link>extensibility\IMethodInfo.cs</Link>
+ </Compile>
+ <Compile Include="..\..\mcs\extensibility\IParameterInfo.cs">
+ <Link>extensibility\IParameterInfo.cs</Link>
+ </Compile>
+ <Compile Include="..\..\mcs\extensibility\ITypeExpression.cs">
+ <Link>extensibility\ITypeExpression.cs</Link>
+ </Compile>
+ <Compile Include="..\..\mcs\extensibility\ITypeExpressionFactory.cs">
+ <Link>extensibility\ITypeExpressionFactory.cs</Link>
+ </Compile>
+ <Compile Include="..\..\mcs\extensibility\ITypeInfo.cs">
+ <Link>extensibility\ITypeInfo.cs</Link>
+ </Compile>
<Compile Include="..\..\mcs\field.cs">
<Link>field.cs</Link>
</Compile>
View
3  mcs/mcs/AssemblyInfo.cs
@@ -41,3 +41,6 @@
[assembly: AssemblyDescription ("Mono C# Compiler")]
+[assembly: AssemblyDelaySign(true)]
+[assembly: AssemblyKeyFile("../class/mono.pub")]
+
View
107 mcs/mcs/add_in_manager.cs
@@ -0,0 +1,107 @@
+//
+// AddInManager:
+// Manages compiler add-ins based on Mono.CompilerServices.Extensibility
+// interfaces.
+//
+// Author: Richard Cook (rcook@rprodev.com)
+//
+
+using System;
+using System.Collections.Generic;
+using System.Configuration;
+using Mono.CSharp;
+using Mono.CompilerServices.Extensibility;
+
+namespace Mono.CSharp
+{
+ internal static class AddInManager
+ {
+ private sealed class TypeExpressionFactory : ITypeExpressionFactory
+ {
+ #region ITypeExpressionFactory Members
+
+ ITypeExpression ITypeExpressionFactory.CreateSimpleTypeExpression(string name, ILocation location)
+ {
+ return new SimpleName(name, (Location)location);
+ }
+
+ #endregion ITypeExpressionFactory Members
+
+ internal TypeExpressionFactory()
+ {
+ }
+ }
+
+ private static IAddIn[] _addIns;
+
+ internal static void LoadAddIns()
+ {
+ _addIns = new IAddIn[0];
+ string addInTypeNamesString = ConfigurationSettings.AppSettings["add-ins"];
+ if (!string.IsNullOrEmpty(addInTypeNamesString))
+ {
+ string[] addInTypeNames = addInTypeNamesString.Split(';');
+ List<IAddIn> addIns = new List<IAddIn>();
+ for (int i = 0; i < addInTypeNames.Length; ++i)
+ {
+ try
+ {
+ Type addInType = Type.GetType(addInTypeNames[i], true, false);
+ object addInObj = Activator.CreateInstance(addInType, false);
+ IAddIn addIn = (IAddIn)addInObj;
+ addIns.Add(addIn);
+ }
+ catch (Exception)
+ {
+ Console.WriteLine("Add-in manager: add-in failed to load.");
+ }
+ }
+ _addIns = addIns.ToArray();
+ }
+ }
+
+ internal static bool ParseCommandLineOption(string arg)
+ {
+ foreach (IAddIn addIn in _addIns)
+ {
+ try
+ {
+ if (addIn.ParseCommandLineOption(arg))
+ {
+ return true;
+ }
+ }
+ catch (Exception)
+ {
+ Console.WriteLine("Add-in manager: add-in failed to parse command line.");
+ }
+ }
+ return false;
+ }
+
+ internal static void ApplyTypeTransforms(IList<TypeContainer> types)
+ {
+ TypeExpressionFactory typeExprFactory = new TypeExpressionFactory();
+ foreach (IAddIn addIn in _addIns)
+ {
+ try
+ {
+ addIn.ApplyTypeTransform(typeExprFactory, Adapt(types));
+ }
+ catch (Exception)
+ {
+ Console.WriteLine("Add-in manager: add-in failed to apply type transform.");
+ }
+ }
+ }
+
+ private static IEnumerable<ITypeInfo> Adapt(IList<TypeContainer> types)
+ {
+ foreach (ITypeInfo type in types)
+ {
+ yield return type;
+ }
+ }
+ }
+}
+
View
21 mcs/mcs/class.cs
@@ -21,6 +21,7 @@
using System.Security.Permissions;
using System.Text;
using System.Linq;
+using Ext = Mono.CompilerServices.Extensibility;
#if NET_2_1
using XmlElement = System.Object;
@@ -2263,7 +2264,25 @@ public override IList<MethodSpec> LookupExtensionMethod (TypeSpec extensionType,
// TODO: should be sealed
- public class Class : ClassOrStruct {
+ public class Class : ClassOrStruct, Ext.ITypeInfo {
+
+ #region ITypeInfo Members
+
+ string Ext.ITypeInfo.Name {get {return Name;}}
+
+ IEnumerable<Ext.IMethodInfo> Ext.ITypeInfo.Methods
+ {
+ get
+ {
+ foreach (Method method in Methods)
+ {
+ yield return method;
+ }
+ }
+ }
+
+ #endregion ITypeInfo Members
+
const Modifiers AllowedModifiers =
Modifiers.NEW |
Modifiers.PUBLIC |
View
18 mcs/mcs/dmcs.csproj
@@ -52,6 +52,8 @@
<Compile Include="..\class\Mono.CompilerServices.SymbolWriter\MonoSymbolWriter.cs">
<Link>MonoSymbolWriter.cs</Link>
</Compile>
+ <Compile Include="add_in_manager.cs">
+ </Compile>
<Compile Include="argument.cs" />
<Compile Include="AssemblyInfo.cs">
</Compile>
@@ -97,6 +99,20 @@
</Compile>
<Compile Include="expression.cs">
</Compile>
+ <Compile Include="extensibility\IAddIn.cs">
+ </Compile>
+ <Compile Include="extensibility\ILocation.cs">
+ </Compile>
+ <Compile Include="extensibility\IMethodInfo.cs">
+ </Compile>
+ <Compile Include="extensibility\IParameterInfo.cs">
+ </Compile>
+ <Compile Include="extensibility\ITypeExpression.cs">
+ </Compile>
+ <Compile Include="extensibility\ITypeExpressionFactory.cs">
+ </Compile>
+ <Compile Include="extensibility\ITypeInfo.cs">
+ </Compile>
<Compile Include="flowanalysis.cs">
</Compile>
<Compile Include="generic.cs" />
@@ -151,4 +167,4 @@
<Target Name="AfterBuild">
</Target>
-->
-</Project>
+</Project>
View
8 mcs/mcs/dmcs.exe.sources
@@ -1,3 +1,4 @@
+add_in_manager.cs
AssemblyInfo.cs
anonymous.cs
argument.cs
@@ -21,6 +22,13 @@ ecore.cs
enum.cs
eval.cs
expression.cs
+extensibility/IAddIn.cs
+extensibility/ILocation.cs
+extensibility/IMethodInfo.cs
+extensibility/IParameterInfo.cs
+extensibility/ITypeExpression.cs
+extensibility/ITypeExpressionFactory.cs
+extensibility/ITypeInfo.cs
field.cs
flowanalysis.cs
generic.cs
View
9 mcs/mcs/driver.cs
@@ -297,6 +297,8 @@ static void About ()
public static int Main (string[] args)
{
+ AddInManager.LoadAddIns();
+
Location.InEmacs = Environment.GetEnvironmentVariable ("EMACS") == "t";
var crp = new ConsoleReportPrinter ();
Driver d = Driver.Create (args, true, crp);
@@ -1573,6 +1575,11 @@ bool CSCParseOption (string option, ref string [] args)
return true;
}
+ if (AddInManager.ParseCommandLineOption(arg))
+ {
+ return true;
+ }
+
return false;
}
@@ -1659,6 +1666,8 @@ public bool Compile ()
if (tokenize || parse_only)
return true;
+ AddInManager.ApplyTypeTransforms(RootContext.ToplevelTypes.Types);
+
if (RootContext.ToplevelTypes.NamespaceEntry != null)
throw new InternalErrorException ("who set it?");
View
20 mcs/mcs/ecore.cs
@@ -18,6 +18,7 @@
using System.Text;
using SLE = System.Linq.Expressions;
using System.Linq;
+using Ext = Mono.CompilerServices.Extensibility;
namespace Mono.CSharp {
@@ -2409,8 +2410,25 @@ Expression SimpleNameResolve (ResolveContext ec, Expression right_side, bool int
/// Represents a namespace or a type. The name of the class was inspired by
/// section 10.8.1 (Fully Qualified Names).
/// </summary>
- public abstract class FullNamedExpression : Expression
+ public abstract class FullNamedExpression : Expression, Ext.ITypeExpression
{
+ #region ITypeExpression Members
+
+ Ext.ILocation Ext.ITypeExpression.Location
+ {
+ get
+ {
+ return Location;
+ }
+ }
+
+ #endregion ITypeExpression Member
+
+ public override string ToString()
+ {
+ return GetSignatureForError();
+ }
+
protected override void CloneTo (CloneContext clonectx, Expression target)
{
// Do nothing, most unresolved type expressions cannot be
View
20 mcs/mcs/extensibility/IAddIn.cs
@@ -0,0 +1,20 @@
+//
+// IAddIn:
+// Provides main entry points for a compiler add-in.
+//
+// Author: Richard Cook (rcook@rprodev.com)
+//
+
+using System.Collections.Generic;
+
+namespace Mono.CompilerServices.Extensibility
+{
+ public interface IAddIn
+ {
+ string Name {get;}
+ string Description {get;}
+ bool ParseCommandLineOption(string arg);
+ void ApplyTypeTransform(ITypeExpressionFactory typeExprFactory, IEnumerable<ITypeInfo> types);
+ }
+}
+
View
14 mcs/mcs/extensibility/ILocation.cs
@@ -0,0 +1,14 @@
+//
+// ILocation:
+// Supplies source code location information.
+//
+// Author: Richard Cook (rcook@rprodev.com)
+//
+
+namespace Mono.CompilerServices.Extensibility
+{
+ public interface ILocation
+ {
+ }
+}
+
View
18 mcs/mcs/extensibility/IMethodInfo.cs
@@ -0,0 +1,18 @@
+//
+// IMethodInfo:
+// Enables basic manipulation of methods.
+//
+// Author: Richard Cook (rcook@rprodev.com)
+//
+
+using System.Collections.Generic;
+
+namespace Mono.CompilerServices.Extensibility
+{
+ public interface IMethodInfo
+ {
+ string Name {get;}
+ IEnumerable<IParameterInfo> Parameters {get;}
+ }
+}
+
View
16 mcs/mcs/extensibility/IParameterInfo.cs
@@ -0,0 +1,16 @@
+//
+// IParameterInfo:
+// Enables basic manipulation of parameters.
+//
+// Author: Richard Cook (rcook@rprodev.com)
+//
+
+namespace Mono.CompilerServices.Extensibility
+{
+ public interface IParameterInfo
+ {
+ string Name {get;}
+ ITypeExpression TypeExpression {get; set;}
+ }
+}
+
View
15 mcs/mcs/extensibility/ITypeExpression.cs
@@ -0,0 +1,15 @@
+//
+// ITypeExpression:
+// Enables basic manipulation of type expressions.
+//
+// Author: Richard Cook (rcook@rprodev.com)
+//
+
+namespace Mono.CompilerServices.Extensibility
+{
+ public interface ITypeExpression
+ {
+ ILocation Location {get;}
+ }
+}
+
View
15 mcs/mcs/extensibility/ITypeExpressionFactory.cs
@@ -0,0 +1,15 @@
+//
+// ITypeExpressionFactory:
+// Allows add-ins to create type expressions.
+//
+// Author: Richard Cook (rcook@rprodev.com)
+//
+
+namespace Mono.CompilerServices.Extensibility
+{
+ public interface ITypeExpressionFactory
+ {
+ ITypeExpression CreateSimpleTypeExpression(string name, ILocation location);
+ }
+}
+
View
18 mcs/mcs/extensibility/ITypeInfo.cs
@@ -0,0 +1,18 @@
+//
+// ITypeInfo:
+// Enables basic manipulation of types.
+//
+// Author: Richard Cook (rcook@rprodev.com)
+//
+
+using System.Collections.Generic;
+
+namespace Mono.CompilerServices.Extensibility
+{
+ public interface ITypeInfo
+ {
+ string Name {get;}
+ IEnumerable<IMethodInfo> Methods {get;}
+ }
+}
+
View
10 mcs/mcs/gmcs.csproj
@@ -46,6 +46,7 @@
<Compile Include="..\class\Mono.CompilerServices.SymbolWriter\MonoSymbolFile.cs" />
<Compile Include="..\class\Mono.CompilerServices.SymbolWriter\MonoSymbolTable.cs" />
<Compile Include="..\class\Mono.CompilerServices.SymbolWriter\MonoSymbolWriter.cs" />
+ <Compile Include="add_in_manager.cs" />
<Compile Include="argument.cs" />
<Compile Include="AssemblyInfo.cs" />
<Compile Include="anonymous.cs" />
@@ -72,6 +73,13 @@
<Compile Include="ecore.cs" />
<Compile Include="enum.cs" />
<Compile Include="expression.cs" />
+ <Compile Include="extensibility\IAddIn.cs" />
+ <Compile Include="extensibility\ILocation.cs" />
+ <Compile Include="extensibility\IMethodInfo.cs" />
+ <Compile Include="extensibility\IParameterInfo.cs" />
+ <Compile Include="extensibility\ITypeExpression.cs" />
+ <Compile Include="extensibility\ITypeExpressionFactory.cs" />
+ <Compile Include="extensibility\ITypeInfo.cs" />
<Compile Include="flowanalysis.cs" />
<Compile Include="generic.cs" />
<Compile Include="iterators.cs" />
@@ -109,4 +117,4 @@
<Target Name="AfterBuild">
</Target>
-->
-</Project>
+</Project>
View
8 mcs/mcs/gmcs.exe.sources
@@ -1,3 +1,4 @@
+add_in_manager.cs
AssemblyInfo.cs
anonymous.cs
argument.cs
@@ -22,6 +23,13 @@ ecore.cs
enum.cs
eval.cs
expression.cs
+extensibility/IAddIn.cs
+extensibility/ILocation.cs
+extensibility/IMethodInfo.cs
+extensibility/IParameterInfo.cs
+extensibility/ITypeExpression.cs
+extensibility/ITypeExpressionFactory.cs
+extensibility/ITypeInfo.cs
field.cs
flowanalysis.cs
generic.cs
View
3  mcs/mcs/location.cs
@@ -16,6 +16,7 @@
using Mono.CompilerServices.SymbolWriter;
using System.Diagnostics;
using System.Linq;
+using Ext = Mono.CompilerServices.Extensibility;
namespace Mono.CSharp {
/// <summary>
@@ -167,7 +168,7 @@ public bool IsConditionalDefined (string value)
///
/// http://lists.ximian.com/pipermail/mono-devel-list/2004-December/009508.html
/// </remarks>
- public struct Location : IEquatable<Location>
+ public struct Location : IEquatable<Location>, Ext.ILocation
{
int token;
View
9 mcs/mcs/mcs-mcs-build
@@ -0,0 +1,9 @@
+#!/bin/bash
+if [[ "$1" == "" ]]; then
+ OPTS="clean all-local install"
+else
+ OPTS=$*
+fi
+CMD="make FRAMEWORK_VERSION=4.0 $OPTS"
+$CMD
+
View
20 mcs/mcs/method.cs
@@ -27,6 +27,7 @@
#else
using System.Xml;
#endif
+using Ext = Mono.CompilerServices.Extensibility;
using Mono.CompilerServices.SymbolWriter;
@@ -761,8 +762,25 @@ public static SourceMethod Create (DeclSpace parent, MethodBase method, Block bl
}
}
- public class Method : MethodOrOperator, IGenericMethodDefinition
+ public class Method : MethodOrOperator, IGenericMethodDefinition, Ext.IMethodInfo
{
+ #region IMethodInfo Members
+
+ string Ext.IMethodInfo.Name {get {return Name;}}
+
+ IEnumerable<Ext.IParameterInfo> Ext.IMethodInfo.Parameters
+ {
+ get
+ {
+ foreach (Parameter parameter in this.ParameterInfo.FixedParameters)
+ {
+ yield return parameter;
+ }
+ }
+ }
+
+ #endregion IMethodMembers
+
Method partialMethodImplementation;
public Method (DeclSpace parent, GenericMethod generic,
View
24 mcs/mcs/parameter.cs
@@ -15,6 +15,7 @@
using System.Reflection.Emit;
using System.Text;
using System.Linq;
+using Ext = Mono.CompilerServices.Extensibility;
namespace Mono.CSharp {
@@ -224,8 +225,26 @@ public interface IParameterData
//
// Parameter information created by parser
//
- public class Parameter : ParameterBase, IParameterData, ILocalVariable // TODO: INamedBlockVariable
+ public class Parameter : ParameterBase, IParameterData, ILocalVariable, Ext.IParameterInfo // TODO: INamedBlockVariable
{
+ #region IParameterInfo Members
+
+ string Ext.IParameterInfo.Name {get {return Name;}}
+
+ Ext.ITypeExpression Ext.IParameterInfo.TypeExpression
+ {
+ get
+ {
+ return TypeExpression;
+ }
+ set
+ {
+ TypeExpression = (FullNamedExpression)value;
+ }
+ }
+
+ #endregion IParameterInfo Members
+
[Flags]
public enum Modifier : byte {
NONE = 0,
@@ -293,6 +312,9 @@ public Parameter (FullNamedExpression type, string name, Modifier mod, Attribute
get {
return texpr;
}
+ set {
+ texpr = value;
+ }
}
public override string[] ValidAttributeTargets {
View
8 mcs/mcs/smcs.exe.sources
@@ -1,3 +1,4 @@
+add_in_manager.cs
AssemblyInfo.cs
anonymous.cs
argument.cs
@@ -21,6 +22,13 @@ enum.cs
ecore.cs
eval.cs
expression.cs
+extensibility/IAddIn.cs
+extensibility/ILocation.cs
+extensibility/IMethodInfo.cs
+extensibility/IParameterInfo.cs
+extensibility/ITypeExpression.cs
+extensibility/ITypeExpressionFactory.cs
+extensibility/ITypeInfo.cs
field.cs
flowanalysis.cs
generic.cs
Please sign in to comment.
Something went wrong with that request. Please try again.