Refactored the Kernel registration fluent interface to be more readable, better suppo...
[castle.git] / MonoRail / Castle.MonoRail.Views.Brail / Macros / DslMacro.cs
blob0f5e0d97e2d0776a3836c70ad490bdafe3004697
1 // Copyright 2004-2008 Castle Project - http://www.castleproject.org/
2 //
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
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
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
17 using System;
18 using System.Collections;
19 using Boo.Lang.Compiler;
20 using Boo.Lang.Compiler.Ast;
21 using Framework;
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);
30 public DslMacro()
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
66 // the dsl reference
67 Block macroBlock = macro.Block;
68 (new NameExpander(dslReference)).Visit(macroBlock);
69 codeBlock.Add(macroBlock);
70 // dsl.Flush();
71 codeBlock.Add(new MethodInvocationExpression(AstUtil.CreateReferenceExpression("dsl.Flush")));
72 return codeBlock;
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))
142 nsPieces.Clear();
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);
183 return;
186 MemberReferenceExpression mre = new MemberReferenceExpression(node.LexicalInfo);
187 mre.Name = node.Name;
188 mre.Target = _reference.CloneNode();
190 ReplaceCurrentNode(mre);
194 #endregion