forked from ayende/rhino-dsl
-
Notifications
You must be signed in to change notification settings - Fork 1
/
MethodSubstitutionBaseClassCompilerStep.cs
108 lines (94 loc) · 3.25 KB
/
MethodSubstitutionBaseClassCompilerStep.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Text;
using Boo.Lang;
using Boo.Lang.Compiler.Ast;
using Module = Boo.Lang.Compiler.Ast.Module;
namespace Rhino.DSL
{
/// <summary>
/// Takes all macro statements that exist in the modules global section and puts the bodies of those methods
/// into corresponding overridable methods on the base class.
/// </summary>
public class MethodSubstitutionBaseClassCompilerStep : BaseClassCompilerStep
{
private readonly DepthFirstTransformer[] transformers;
/// <summary>
/// Create an instance of MethodSubstitutionBaseClassCompilerStep
/// </summary>
public MethodSubstitutionBaseClassCompilerStep(Type baseClassType, params string[] namespaces)
: base(baseClassType, namespaces)
{
}
/// <summary>
/// Create an instance of MethodSubstitutionBaseClassCompilerStep
/// </summary>
public MethodSubstitutionBaseClassCompilerStep(Type baseClass, DepthFirstTransformer[] transformers, params string[] namespaces)
: base(baseClass, namespaces)
{
this.transformers = transformers;
}
/// <summary>
/// Extends the base class by placing the blocks of macros into methods on the base class
/// of the same name.
/// </summary>
/// <example>
/// MyMethod:
/// PerformActions
///
/// If an overridable method called MyMethod exists on <see cref="BaseClassCompilerStep.BaseClass"/>, then
/// it is overridden as follows:
/// <code>
/// public override void MyMethod() { PerformActions(); }
/// </code>
/// </example>
protected override void ExtendBaseClass(Module module, ClassDefinition definition)
{
List<MethodInfo> methodsThatAreOverridable = new List<MethodInfo>();
MethodInfo[] baseClassMethods =
BaseClass.GetMethods(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public |
BindingFlags.InvokeMethod);
foreach (MethodInfo method in baseClassMethods)
{
if(method.DeclaringType==typeof(object))
continue;
if (method.IsVirtual || method.IsAbstract)
methodsThatAreOverridable.Add(method);
}
MethodSubstitutionTransformer mst = new MethodSubstitutionTransformer(methodsThatAreOverridable.ToArray(), definition);
mst.Visit(module);
if (transformers != null)
{
foreach (DepthFirstTransformer transformer in transformers)
transformer.Visit(module);
}
}
private class MethodSubstitutionTransformer : DepthFirstTransformer
{
private readonly ClassDefinition classDefinition;
private readonly MethodInfo[] methods;
public MethodSubstitutionTransformer(MethodInfo[] methods, ClassDefinition classDefinition)
{
this.classDefinition = classDefinition;
this.methods = methods;
}
public override void OnMacroStatement(MacroStatement node)
{
MethodInfo methodToOverride = Array.Find(methods, delegate(MethodInfo mi) { return mi.Name.Equals(node.Name); });
if (methodToOverride != null)
{
Method method = new Method(node.LexicalInfo);
method.Name = node.Name;
method.Body = node.Block;
classDefinition.Members.Add(method);
}
else
{
base.OnMacroStatement(node);
}
}
}
}
}