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
17 using System
.Collections
;
18 using Boo
.Lang
.Compiler
;
19 using Boo
.Lang
.Compiler
.Ast
;
20 using Boo
.Lang
.Compiler
.TypeSystem
;
24 public class ComponentMacro
: AbstractAstMacro
26 private string componentContextName
;
27 private string componentFactoryName
;
28 private string componentVariableName
;
30 public override Statement
Expand(MacroStatement macro
)
32 componentContextName
= ComponentNaming
.GetComponentContextName(macro
);
33 componentFactoryName
= ComponentNaming
.GetComponentFactoryName(macro
);
34 componentVariableName
= ComponentNaming
.GetComponentNameFor(macro
);
36 if (macro
.Arguments
.Count
== 0) throw new MonoRailException("Component must be called with a name");
38 Block block
= new Block();
42 method
= (Method
) macro
.GetAncestor(NodeType
.Method
);
44 StringLiteralExpression componentName
= new StringLiteralExpression(macro
.Arguments
[0].ToString());
46 MethodInvocationExpression dictionary
= CreateParametersDictionary(macro
);
48 Expression macroBody
= CodeBuilderHelper
.CreateCallableFromMacroBody(CodeBuilder
, macro
);
50 MethodInvocationExpression initContext
= new MethodInvocationExpression();
51 initContext
.Target
= AstUtil
.CreateReferenceExpression("Castle.MonoRail.Views.Brail.BrailViewComponentContext");
52 initContext
.Arguments
.Extend(
55 new SelfLiteralExpression(),
56 macroBody
, componentName
,
57 AstUtil
.CreateReferenceExpression("OutputStream"),
61 // compilerContext = BrailViewComponentContext(macroBodyClosure, "componentName", OutputStream, dictionary)
62 block
.Add(new BinaryExpression(BinaryOperatorType
.Assign
,
63 new ReferenceExpression(componentContextName
), initContext
));
65 // AddViewComponentProperties( compilerContext.ComponentParams )
66 MethodInvocationExpression addProperties
=
67 new MethodInvocationExpression(AstUtil
.CreateReferenceExpression("AddViewComponentProperties"));
68 addProperties
.Arguments
.Add(AstUtil
.CreateReferenceExpression(componentContextName
+ ".ComponentParameters"));
69 block
.Add(addProperties
);
71 InternalLocal viewComponentFactoryLocal
= CodeBuilder
.DeclareLocal(method
, componentFactoryName
,
72 TypeSystemServices
.Map(
73 typeof(IViewComponentFactory
)));
75 // viewComponentFactory = context.GetService(IViewComponentFactory)
76 MethodInvocationExpression callService
= new MethodInvocationExpression(
77 AstUtil
.CreateReferenceExpression("context.GetService"));
78 callService
.Arguments
.Add(CodeBuilder
.CreateTypeofExpression(typeof(IViewComponentFactory
)));
80 block
.Add(new BinaryExpression(BinaryOperatorType
.Assign
,
81 CodeBuilder
.CreateLocalReference(componentFactoryName
, viewComponentFactoryLocal
),
84 // component = viewComponentFactory.Create( componentName)
85 MethodInvocationExpression createComponent
= new MethodInvocationExpression(
86 new MemberReferenceExpression(CodeBuilder
.CreateLocalReference(componentFactoryName
, viewComponentFactoryLocal
),
88 createComponent
.Arguments
.Add(componentName
);
89 block
.Add(new BinaryExpression(BinaryOperatorType
.Assign
,
90 new ReferenceExpression(componentVariableName
),
92 AddSections(block
, macro
);
94 // component.Init(context, componentContext)
95 MethodInvocationExpression initComponent
= new MethodInvocationExpression(
96 AstUtil
.CreateReferenceExpression(componentVariableName
+ ".Init"));
97 initComponent
.Arguments
.Extend(
100 new ReferenceExpression("context"),
101 new ReferenceExpression(componentContextName
)
104 block
.Add(initComponent
);
106 // component.Render()
107 block
.Add(new MethodInvocationExpression(
108 AstUtil
.CreateReferenceExpression(componentVariableName
+ ".Render")));
110 // if component.ViewToRender is not null:
111 // OutputSubView("/"+component.ViewToRender, context.CompnentParameters)
112 Block renderView
= new Block();
113 MethodInvocationExpression outputSubView
= new MethodInvocationExpression(
114 AstUtil
.CreateReferenceExpression("OutputSubView"));
115 outputSubView
.Arguments
.Add(new BinaryExpression(BinaryOperatorType
.Addition
,
116 new StringLiteralExpression("/"),
117 AstUtil
.CreateReferenceExpression(componentContextName
+
120 outputSubView
.Arguments
.Add(AstUtil
.CreateReferenceExpression(componentContextName
+ ".ComponentParameters"));
121 renderView
.Add(outputSubView
);
123 block
.Add(new IfStatement(AstUtil
.CreateReferenceExpression(componentContextName
+ ".ViewToRender"),
124 renderView
, new Block()));
126 // RemoveViewComponentProperties( compilerContext.ComponentParams )
127 MethodInvocationExpression removeProperties
=
128 new MethodInvocationExpression(AstUtil
.CreateReferenceExpression("RemoveViewComponentProperties"));
129 removeProperties
.Arguments
.Add(AstUtil
.CreateReferenceExpression(componentContextName
+ ".ComponentParameters"));
130 block
.Add(removeProperties
);
135 private static void AddSections(Block block
, Node macro
)
137 IDictionary sections
= (IDictionary
) macro
["sections"];
139 if (sections
== null) return;
141 foreach(DictionaryEntry entry
in sections
)
143 block
.Add((Block
) entry
.Value
);
147 private static MethodInvocationExpression
CreateParametersDictionary(MacroStatement macro
)
149 // Make sure that hash table is an case insensitive one.
150 MethodInvocationExpression dictionary
= new MethodInvocationExpression();
151 dictionary
.Target
= AstUtil
.CreateReferenceExpression("System.Collections.Hashtable");
153 //If component has parameters, add them
154 if (macro
.Arguments
.Count
== 2)
156 dictionary
.Arguments
.Add(macro
.Arguments
[1]);
159 dictionary
.Arguments
.Add(
160 AstUtil
.CreateReferenceExpression("System.Collections.CaseInsensitiveHashCodeProvider.Default"));
161 dictionary
.Arguments
.Add(AstUtil
.CreateReferenceExpression("System.Collections.CaseInsensitiveComparer.Default"));