typo (spotted by tamara)
[boo.git] / src / Boo.Lang.Compiler / Attributes / PropertyAttribute.cs
blobd48771d92b5c774bd2d1106caa6503a67bccf54e
1 #region license
2 // Copyright (c) 2004, Rodrigo B. de Oliveira (rbo@acm.org)
3 // All rights reserved.
4 //
5 // Redistribution and use in source and binary forms, with or without modification,
6 // are permitted provided that the following conditions are met:
7 //
8 // * Redistributions of source code must retain the above copyright notice,
9 // this list of conditions and the following disclaimer.
10 // * Redistributions in binary form must reproduce the above copyright notice,
11 // this list of conditions and the following disclaimer in the documentation
12 // and/or other materials provided with the distribution.
13 // * Neither the name of Rodrigo B. de Oliveira nor the names of its
14 // contributors may be used to endorse or promote products derived from this
15 // software without specific prior written permission.
16 //
17 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
18 // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19 // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20 // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
21 // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
23 // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
24 // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
25 // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 // THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 #endregion
29 using System;
30 using Boo.Lang.Compiler.Ast;
32 namespace Boo.Lang
34 /// <summary>
35 /// Creates a property over a field.
36 /// </summary>
37 public class PropertyAttribute : Boo.Lang.Compiler.AbstractAstAttribute
39 protected ReferenceExpression _propertyName;
41 protected Expression _setPreCondition;
43 protected BoolLiteralExpression _protected;
45 protected BoolLiteralExpression _observable;
47 protected ListLiteralExpression _attributes;
49 public PropertyAttribute(ReferenceExpression propertyName) : this(propertyName, null)
53 public PropertyAttribute(ReferenceExpression propertyName, Expression setPreCondition)
55 if (null == propertyName)
57 throw new ArgumentNullException("propertyName");
59 _propertyName = propertyName;
60 _setPreCondition = setPreCondition;
63 public BoolLiteralExpression Protected
65 get
67 return _protected;
70 set
72 _protected = value;
76 protected bool IsProtected
78 get
80 if (null == _protected)
82 return false;
84 return _protected.Value;
88 public BoolLiteralExpression Observable
90 get
92 return _observable;
95 set
97 _observable = value;
101 protected bool IsObservable
105 if (null == _observable)
107 return false;
109 return _observable.Value;
113 protected string ChangedEventName
117 return _propertyName.Name + "Changed";
121 public ListLiteralExpression Attributes
125 return _attributes;
130 _attributes = value;
134 override public void Apply(Node node)
136 Field f = node as Field;
137 if (null == f)
139 InvalidNodeForAttribute("Field");
140 return;
143 Property p = new Property();
144 if (f.IsStatic)
146 p.Modifiers |= TypeMemberModifiers.Static;
148 if (IsProtected)
150 p.Modifiers |= TypeMemberModifiers.Protected;
152 p.Name = _propertyName.Name;
153 p.Type = f.Type;
154 p.Getter = CreateGetter(f);
155 p.Setter = CreateSetter(f);
156 p.LexicalInfo = LexicalInfo;
158 if (Attributes != null && Attributes.Items.Count > 0)
160 foreach (Expression item in Attributes.Items)
162 p.Attributes.Add(ConvertExpressionToAttribute(item));
166 f.DeclaringType.Members.Add(p);
168 if (IsObservable)
170 f.DeclaringType.Members.Add(CreateChangedEvent(f));
174 static public Boo.Lang.Compiler.Ast.Attribute ConvertExpressionToAttribute(
175 Expression item)
177 Boo.Lang.Compiler.Ast.Attribute att =
178 new Boo.Lang.Compiler.Ast.Attribute(item.LexicalInfo);
179 if (item is MethodInvocationExpression)
181 MethodInvocationExpression m = (MethodInvocationExpression)item;
182 att.Name = m.Target.ToString();
183 att.Arguments = m.Arguments;
184 att.NamedArguments = m.NamedArguments;
186 else
188 att.Name = item.ToString();
190 return att;
193 virtual protected Method CreateGetter(Field f)
195 // get:
196 // return <f.Name>
197 Method getter = new Method();
198 getter.Name = "get";
199 getter.Body.Statements.Add(
200 new ReturnStatement(
201 base.LexicalInfo,
202 new ReferenceExpression(f.Name),
203 null)
205 return getter;
208 virtual protected Method CreateSetter(Field f)
210 Method setter = new Method();
211 setter.Name = "set";
213 if (null != _setPreCondition)
215 setter.Body.Add(
216 new RaiseStatement(
217 _setPreCondition.LexicalInfo,
218 AstUtil.CreateMethodInvocationExpression(
219 AstUtil.CreateReferenceExpression("System.ArgumentException"),
220 new StringLiteralExpression("precondition '" +
221 _setPreCondition.ToString() +
222 "' failed:")),
223 new StatementModifier(
224 StatementModifierType.Unless,
225 _setPreCondition)));
227 setter.Body.Add(
228 new BinaryExpression(
229 base.LexicalInfo,
230 BinaryOperatorType.Assign,
231 new MemberReferenceExpression(
232 CreateRefTarget(f),
233 f.Name),
234 new ReferenceExpression("value")
238 if (IsObservable)
240 MethodInvocationExpression mie = new MethodInvocationExpression(
241 new ReferenceExpression(ChangedEventName));
242 mie.Arguments.Add(new SelfLiteralExpression());
243 mie.Arguments.Add(
244 new MemberReferenceExpression(
245 new MemberReferenceExpression(
246 new ReferenceExpression("System"),
247 "EventArgs"),
248 "Empty"));
249 setter.Body.Add(mie);
251 return setter;
254 private Expression CreateRefTarget(Field f)
256 if (f.IsStatic) return new ReferenceExpression(LexicalInfo, f.DeclaringType.Name);
257 return new SelfLiteralExpression(LexicalInfo);
260 protected Event CreateChangedEvent(Field f)
262 Event e = new Event(_observable.LexicalInfo);
263 e.Name = ChangedEventName;
264 e.Type = CodeBuilder.CreateTypeReference(f.LexicalInfo, typeof(System.EventHandler));
265 return e;