1 // Copyright 2004-2007 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
;
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);
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 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
))
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
);
189 MemberReferenceExpression mre
= new MemberReferenceExpression(node
.LexicalInfo
);
190 mre
.Name
= node
.Name
;
191 mre
.Target
= _reference
.CloneNode();
193 ReplaceCurrentNode(mre
);