1 // Copyright 2004-2008 Castle Project - http://www.castleproject.org/
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
7 // http://www.apache.org/licenses/LICENSE-2.0
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
15 namespace Castle
.MonoRail
.Views
.Brail
18 using System
.Collections
;
19 using Boo
.Lang
.Compiler
;
20 using Boo
.Lang
.Compiler
.Ast
;
22 using System
.Collections
.Specialized
;
23 using System
.Collections
.Generic
;
24 using System
.Reflection
;
26 public class DslMacro
: AbstractAstMacro
28 private readonly IDictionary languages
= new HybridDictionary(true);
32 languages
.Add("html", typeof(HtmlExtension
));
33 languages
.Add("xml", typeof(XmlExtension
));
36 public override Statement
Expand(MacroStatement macro
)
38 Block codeBlock
= new Block();
40 // Castle.MonoRail.Views.Brail.DslProvider(BrailBase)
41 MethodInvocationExpression newDslWrapper
= new MethodInvocationExpression();
42 newDslWrapper
.Target
= AstUtil
.CreateReferenceExpression("Castle.MonoRail.Views.Brail.DslProvider");
43 newDslWrapper
.Arguments
.Add(new SelfLiteralExpression());
45 // dsl = Castle.MonoRail.Views.Brail.DslPRovider(BrailBase)
46 ReferenceExpression dslReference
= AstUtil
.CreateReferenceExpression("dsl");
47 codeBlock
.Add(new BinaryExpression(BinaryOperatorType
.Assign
, dslReference
, newDslWrapper
));
49 if (macro
.Arguments
.Count
== 1)
51 string language
= LookupLanguageExtension(macro
.Arguments
[0].ToString());
52 // LanguageExtension(OutputStream)
53 MethodInvocationExpression newLanguage
= new MethodInvocationExpression();
54 newLanguage
.Target
= AstUtil
.CreateReferenceExpression(language
);
55 newLanguage
.Arguments
.Add(AstUtil
.CreateReferenceExpression("OutputStream"));
57 MethodInvocationExpression registerLanguage
= new MethodInvocationExpression();
58 registerLanguage
.Target
= AstUtil
.CreateReferenceExpression("dsl.Register");
59 registerLanguage
.Arguments
.Add(newLanguage
);
61 // dsl.Register(LanguageExtension(OutputStream))
62 codeBlock
.Add(registerLanguage
);
65 // rewrite the remaining code to invoke methods on
67 Block macroBlock
= macro
.Block
;
68 (new NameExpander(dslReference
)).Visit(macroBlock
);
69 codeBlock
.Add(macroBlock
);
71 codeBlock
.Add(new MethodInvocationExpression(AstUtil
.CreateReferenceExpression("dsl.Flush")));
75 private string LookupLanguageExtension(string language
)
77 if (!languages
.Contains(language
))
79 throw new MonoRailException(string.Format("Language '{0}' is not implemented", language
));
82 Type languageExtension
= (Type
) languages
[language
];
83 return string.Format("{0}{1}{2}", languageExtension
.Namespace
, Type
.Delimiter
, languageExtension
.Name
);
86 #region Nested type: NameExpander
88 private class NameExpander
: DepthFirstTransformer
90 private readonly ReferenceExpression _reference
= null;
91 private readonly IDictionary
<string, Node
> _skippedReferences
= null;
92 private readonly IDictionary
<string, Type
> _splitNamespaces
= null;
94 public NameExpander(ReferenceExpression reference
)
96 _reference
= reference
;
97 _skippedReferences
= new Dictionary
<string, Node
>();
98 _splitNamespaces
= new Dictionary
<string, Type
>();
100 RecordReferenceTypesToSkip(typeof(BrailBase
).Assembly
);
102 foreach(AssemblyName asn
in typeof(BrailBase
).Assembly
.GetReferencedAssemblies())
104 RecordReferenceTypesToSkip(Assembly
.Load(asn
));
107 foreach(MethodInfo method
in typeof(BrailBase
).GetMethods())
109 if (!_skippedReferences
.ContainsKey(method
.Name
))
111 _skippedReferences
.Add(method
.Name
, new MemberReferenceExpression(new SelfLiteralExpression(), method
.Name
));
116 private void RecordReferenceTypesToSkip(Assembly asm
)
118 foreach(Type type
in asm
.GetExportedTypes())
120 SplitTypeNameAndRecordReferenceToSkip(type
);
122 string keyName
= string.Format("{0}{1}{2}", type
.Namespace
, Type
.Delimiter
, type
.Name
);
124 if (!_skippedReferences
.ContainsKey(keyName
))
126 _skippedReferences
.Add(keyName
, new ReferenceExpression(keyName
));
129 if (!_skippedReferences
.ContainsKey(type
.Name
))
131 _skippedReferences
.Add(type
.Name
, new ReferenceExpression(type
.Name
));
136 private void SplitTypeNameAndRecordReferenceToSkip(Type type
)
138 List
<string> nsPieces
= new List
<string>();
140 if (type
.Namespace
!= null && !_splitNamespaces
.ContainsKey(type
.Namespace
))
144 foreach(string nsPart
in type
.Namespace
.Split(Type
.Delimiter
))
146 nsPieces
.Add(nsPart
);
147 string nsItem
= string.Join(new string(Type
.Delimiter
, 1), nsPieces
.ToArray());
149 if (!_skippedReferences
.ContainsKey(nsPart
))
151 _skippedReferences
.Add(nsPart
, new ReferenceExpression(nsPart
));
154 if (!_skippedReferences
.ContainsKey(nsItem
))
156 _skippedReferences
.Add(nsItem
, new ReferenceExpression(nsItem
));
160 _splitNamespaces
.Add(type
.Namespace
, type
);
164 public override void OnDeclaration(Declaration node
)
166 if (!_skippedReferences
.ContainsKey(node
.Name
))
168 _skippedReferences
.Add(node
.Name
, node
);
171 base.OnDeclaration(node
);
174 public override void OnReferenceExpression(ReferenceExpression node
)
176 if (node
.ParentNode
is BinaryExpression
|| _skippedReferences
.ContainsKey(node
.Name
))
178 base.OnReferenceExpression(node
);
179 if (!_skippedReferences
.ContainsKey(node
.Name
))
181 _skippedReferences
.Add(node
.Name
, node
);
186 MemberReferenceExpression mre
= new MemberReferenceExpression(node
.LexicalInfo
);
187 mre
.Name
= node
.Name
;
188 mre
.Target
= _reference
.CloneNode();
190 ReplaceCurrentNode(mre
);