- Implemented support for view component caching. Just use the attribute
[castle.git] / MonoRail / Castle.MonoRail.Views.Brail / Macros / DslMacro.cs
blob62c0bd1958cb1e6d998b53483df22a3aeda342c2
1 // Copyright 2004-2007 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 Castle.MonoRail.Framework;
22 using System.Collections.Specialized;
23 using System.Collections.Generic;
24 using System.Reflection;
26 public class DslMacro : AbstractAstMacro
28 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 private class NameExpander : DepthFirstTransformer
88 readonly ReferenceExpression _reference = null;
89 readonly IDictionary<string, Node> _skippedReferences = null;
90 readonly IDictionary<string, Type> _splitNamespaces = null;
92 public NameExpander(ReferenceExpression reference)
94 _reference = reference;
95 _skippedReferences = new Dictionary<string, Node>();
96 _splitNamespaces = new Dictionary<string, Type>();
98 RecordReferenceTypesToSkip(typeof(BrailBase).Assembly);
100 foreach (AssemblyName asn in typeof(BrailBase).Assembly.GetReferencedAssemblies())
102 RecordReferenceTypesToSkip(Assembly.Load(asn));
105 foreach (MethodInfo method in typeof(BrailBase).GetMethods())
107 if (!_skippedReferences.ContainsKey(method.Name))
109 _skippedReferences.Add(method.Name, new MemberReferenceExpression(new SelfLiteralExpression(), method.Name));
114 private void RecordReferenceTypesToSkip(Assembly asm)
116 foreach (Type type in asm.GetExportedTypes())
118 SplitTypeNameAndRecordReferenceToSkip(type);
120 string keyName = string.Format("{0}{1}{2}", type.Namespace, Type.Delimiter, type.Name);
122 if (!_skippedReferences.ContainsKey(keyName))
124 _skippedReferences.Add(keyName, new ReferenceExpression(keyName));
127 if (!_skippedReferences.ContainsKey(type.Name))
129 _skippedReferences.Add(type.Name, new ReferenceExpression(type.Name));
134 private void SplitTypeNameAndRecordReferenceToSkip(Type type)
136 List<string> nsPieces = new List<string>();
138 if (!_splitNamespaces.ContainsKey(type.Namespace))
140 nsPieces.Clear();
142 foreach (string nsPart in type.Namespace.Split(Type.Delimiter))
144 nsPieces.Add(nsPart);
145 string nsItem = string.Join(new string(Type.Delimiter, 1), nsPieces.ToArray());
147 if (!_skippedReferences.ContainsKey(nsPart))
149 _skippedReferences.Add(nsPart, new ReferenceExpression(nsPart));
152 if (!_skippedReferences.ContainsKey(nsItem))
154 _skippedReferences.Add(nsItem, new ReferenceExpression(nsItem));
158 _splitNamespaces.Add(type.Namespace, type);
162 public override void OnForStatement(ForStatement node)
164 base.OnForStatement(node);
167 public override void OnDeclaration(Declaration node)
169 if (!_skippedReferences.ContainsKey(node.Name))
171 _skippedReferences.Add(node.Name, node);
174 base.OnDeclaration(node);
177 public override void OnReferenceExpression(ReferenceExpression node)
179 if (node.ParentNode is BinaryExpression || _skippedReferences.ContainsKey(node.Name))
181 base.OnReferenceExpression(node);
182 if (!_skippedReferences.ContainsKey(node.Name))
184 _skippedReferences.Add(node.Name, node);
186 return;
189 MemberReferenceExpression mre = new MemberReferenceExpression(node.LexicalInfo);
190 mre.Name = node.Name;
191 mre.Target = _reference.CloneNode();
193 ReplaceCurrentNode(mre);