2010-03-12 Jb Evain <jbevain@novell.com>
[mono.git] / mcs / class / System.Data.Linq / src / DbMetal / Generator / CodeWriter.cs
1 #region MIT license\r
2 // \r
3 // MIT license\r
4 //\r
5 // Copyright (c) 2007-2008 Jiri Moudry, Pascal Craponne\r
6 // \r
7 // Permission is hereby granted, free of charge, to any person obtaining a copy\r
8 // of this software and associated documentation files (the "Software"), to deal\r
9 // in the Software without restriction, including without limitation the rights\r
10 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\r
11 // copies of the Software, and to permit persons to whom the Software is\r
12 // furnished to do so, subject to the following conditions:\r
13 // \r
14 // The above copyright notice and this permission notice shall be included in\r
15 // all copies or substantial portions of the Software.\r
16 // \r
17 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r
18 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r
19 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\r
20 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\r
21 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\r
22 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\r
23 // THE SOFTWARE.\r
24 // \r
25 #endregion\r
26 using System;\r
27 using System.Collections.Generic;\r
28 using System.IO;\r
29 using System.Linq;\r
30 using System.Text;\r
31 using DbLinq.Util;\r
32 using DbMetal.Generator;\r
33 \r
34 namespace DbMetal.Generator\r
35 {\r
36     /// <summary>\r
37     /// Base class for writing code.\r
38     /// Divided in 3 Parts:\r
39     /// - Code line writing (with indentation)\r
40     /// - Code formatting (returning a literal type)\r
41     /// - Code writing (comment line, field, property, event...)\r
42     /// </summary>\r
43     public abstract class CodeWriter : TextWriter\r
44     {\r
45         // required by TextWriter\r
46         public override Encoding Encoding\r
47         {\r
48             get\r
49             {\r
50                 return TextWriter.Encoding;\r
51             }\r
52         }\r
53 \r
54         public string IndentationPattern { get; set; }\r
55 \r
56         private readonly StringBuilder buffer = new StringBuilder(10 << 10);\r
57         private int currentindentation = 0;\r
58 \r
59         protected TextWriter TextWriter;\r
60 \r
61         protected CodeWriter(TextWriter textWriter)\r
62         {\r
63             IndentationPattern = "\t";\r
64             TextWriter = textWriter;\r
65         }\r
66 \r
67         #region Writer\r
68 \r
69         protected bool IsFullLine()\r
70         {\r
71             int endIndex = buffer.Length - CoreNewLine.Length;\r
72             if (endIndex < 0)\r
73                 return false;\r
74             for (int i = 0; i < CoreNewLine.Length; i++)\r
75             {\r
76                 if (buffer[endIndex + i] != CoreNewLine[i])\r
77                     return false;\r
78             }\r
79             return true;\r
80         }\r
81 \r
82         protected string GetLine()\r
83         {\r
84             string line = buffer.ToString();\r
85             buffer.Remove(0, buffer.Length);\r
86             return line;\r
87         }\r
88 \r
89         protected abstract bool MustIndent(string line);\r
90         protected abstract bool MustUnindent(string line);\r
91 \r
92         /// <summary>\r
93         /// In the end, all output comes to this\r
94         /// </summary>\r
95         /// <param name="value"></param>\r
96         public override void Write(char value)\r
97         {\r
98             buffer.Append(value);\r
99             if (IsFullLine())\r
100             {\r
101                 string line = GetLine();\r
102                 string rawLine = Trim(line);\r
103                 // unindent before...\r
104                 if (MustUnindent(rawLine))\r
105                     currentindentation--;\r
106                 WriteLine(rawLine, currentindentation);\r
107                 // indent after\r
108                 if (MustIndent(rawLine))\r
109                     currentindentation++;\r
110             }\r
111         }\r
112 \r
113         protected virtual string Trim(string line)\r
114         {\r
115             return line.Trim();\r
116         }\r
117 \r
118         protected virtual void WriteLine(string rawLine, int indentation)\r
119         {\r
120             if (!string.IsNullOrEmpty(rawLine))\r
121             {\r
122                 for (int indentationCount = 0; indentationCount < indentation; indentationCount++)\r
123                 {\r
124                     TextWriter.Write(IndentationPattern);\r
125                 }\r
126             }\r
127             TextWriter.WriteLine(rawLine);\r
128         }\r
129 \r
130         public virtual string GetEnumType(string name)\r
131         {\r
132             return name;\r
133         }\r
134 \r
135         public abstract IDisposable WriteEnum(SpecificationDefinition specificationDefinition, string name);\r
136 \r
137         public virtual void WriteEnum(SpecificationDefinition specificationDefinition, string name, IDictionary<string, int> values)\r
138         {\r
139             using (WriteEnum(specificationDefinition, name))\r
140             {\r
141                 var orderedValues = from nv in values orderby nv.Value select nv;\r
142                 int currentValue = 1;\r
143                 foreach (var nameValue in orderedValues)\r
144                 {\r
145                     if (nameValue.Value == currentValue)\r
146                         WriteLine(string.Format("{0},", nameValue.Key));\r
147                     else\r
148                     {\r
149                         currentValue = nameValue.Value;\r
150                         WriteLine(string.Format("{0} = {1},", nameValue.Key, nameValue.Value));\r
151                     }\r
152                     currentValue++;\r
153                 }\r
154             }\r
155         }\r
156 \r
157         #endregion\r
158 \r
159         #region Code generation\r
160 \r
161         // A language sometimes generates complementary text, such as "{" and "}", or "#region"/"#endregion"\r
162 \r
163         protected class NestedInstruction : IDisposable\r
164         {\r
165             private readonly Action endAction;\r
166 \r
167             public NestedInstruction(Action end)\r
168             {\r
169                 endAction = end;\r
170             }\r
171 \r
172             public void Dispose()\r
173             {\r
174                 endAction();\r
175             }\r
176         }\r
177 \r
178         /// <summary>\r
179         /// Registers an "end block" (written on Dispose() call)\r
180         /// </summary>\r
181         /// <param name="end"></param>\r
182         /// <returns></returns>\r
183         protected IDisposable EndAction(Action end)\r
184         {\r
185             return new NestedInstruction(end);\r
186         }\r
187 \r
188         #endregion\r
189 \r
190         #region Code generation - Language write\r
191 \r
192         public abstract void WriteCommentLine(string line);\r
193         public virtual void WriteCommentLines(string comments)\r
194         {\r
195             string[] commentLines = comments.Split('\n');\r
196             foreach (string commentLine in commentLines)\r
197             {\r
198                 WriteCommentLine(commentLine.TrimEnd());\r
199             }\r
200         }\r
201 \r
202         /// <summary>\r
203         /// Registers namespace to be written\r
204         /// </summary>\r
205         /// <param name="name"></param>\r
206         public abstract void WriteUsingNamespace(string name);\r
207         public abstract IDisposable WriteNamespace(string name);\r
208         public abstract IDisposable WriteClass(SpecificationDefinition specificationDefinition, string name,\r
209                                                string baseClass, params string[] interfaces);\r
210 \r
211         public abstract IDisposable WriteRegion(string name);\r
212         public abstract IDisposable WriteAttribute(AttributeDefinition attributeDefinition);\r
213 \r
214         public abstract IDisposable WriteCtor(SpecificationDefinition specificationDefinition, string name,\r
215                                               ParameterDefinition[] parameters, IList<string> baseCallParameters);\r
216         public abstract IDisposable WriteMethod(SpecificationDefinition specificationDefinition, string name, Type returnType,\r
217                                                 params ParameterDefinition[] parameters);\r
218 \r
219         public abstract IDisposable WriteProperty(SpecificationDefinition specificationDefinition, string name, string propertyType);\r
220         public abstract void WriteAutomaticPropertyGetSet();\r
221         public abstract IDisposable WritePropertyGet();\r
222         public abstract IDisposable WritePropertySet();\r
223 \r
224         public abstract void WritePropertyWithBackingField(SpecificationDefinition specificationDefinition, string name, string propertyType, bool privateSetter);\r
225         public virtual void WritePropertyWithBackingField(SpecificationDefinition specificationDefinition, string name, string propertyType)\r
226         {\r
227             WritePropertyWithBackingField(specificationDefinition, name, propertyType, false);\r
228         }\r
229 \r
230         public abstract void WriteField(SpecificationDefinition specificationDefinition, string name, string fieldType);\r
231 \r
232         public abstract void WriteEvent(SpecificationDefinition specificationDefinition, string name, string eventDelegate);\r
233 \r
234         public abstract IDisposable WriteIf(string expression);\r
235 \r
236         #endregion\r
237 \r
238         #region Code generation - Language construction\r
239 \r
240         public abstract string GetCastExpression(string value, string castType, bool hardCast);\r
241 \r
242         public virtual string GetLiteralValue(object value)\r
243         {\r
244             if (value == null)\r
245                 return GetNullExpression();\r
246             if (value is string)\r
247                 return string.Format("\"{0}\"", value);\r
248             return value.ToString();\r
249         }\r
250 \r
251         public virtual string GetLiteralType(Type type)\r
252         {\r
253             return type.Name;\r
254         }\r
255 \r
256         public virtual string GetLiteralFullType(Type type)\r
257         {\r
258             return type.FullName;\r
259         }\r
260 \r
261         public virtual string GetMemberExpression(string obj, string member)\r
262         {\r
263             return string.Format("{0}.{1}", obj, member);\r
264         }\r
265 \r
266         public virtual string GetReturnStatement(string expression)\r
267         {\r
268             if (expression == null)\r
269                 return GetStatement("return");\r
270             return GetStatement(string.Format("return {0}", expression));\r
271         }\r
272 \r
273         /// <summary>\r
274         /// Returns the specified variable as a safe expression\r
275         /// </summary>\r
276         /// <param name="name"></param>\r
277         /// <returns></returns>\r
278         public abstract string GetVariableExpression(string name);\r
279 \r
280         public virtual string GetNewExpression(string ctor)\r
281         {\r
282             return string.Format("new {0}", ctor);\r
283         }\r
284 \r
285         public virtual string GetThisExpression()\r
286         {\r
287             return "this";\r
288         }\r
289 \r
290         public virtual string GetDeclarationExpression(string variable, string type)\r
291         {\r
292             return string.Format("{0} {1}", type, variable);\r
293         }\r
294 \r
295         public virtual string GetAssignmentExpression(string variable, string expression)\r
296         {\r
297             return string.Format("{0} = {1}", variable, expression);\r
298         }\r
299 \r
300         public abstract string GetArray(string array, string literalIndex);\r
301 \r
302         public virtual string GetMethodCallExpression(string method, params string[] literalParameters)\r
303         {\r
304             return string.Format("{0}({1})", method, string.Join(", ", literalParameters));\r
305         }\r
306 \r
307         public virtual string GetStatement(string expression)\r
308         {\r
309             return expression;\r
310         }\r
311 \r
312         public abstract string GetPropertySetValueExpression();\r
313 \r
314         public abstract string GetNullExpression();\r
315 \r
316         public abstract string GetGenericName(string baseName, string type);\r
317 \r
318         public abstract string GetDifferentExpression(string a, string b);\r
319         public abstract string GetEqualExpression(string a, string b);\r
320 \r
321         public abstract string GetXOrExpression(string a, string b);\r
322         public abstract string GetAndExpression(string a, string b);\r
323 \r
324         public abstract string GetTernaryExpression(string conditionExpression, string trueExpression, string falseExpression);\r
325 \r
326         public abstract string GetNullValueExpression(string literalType);\r
327 \r
328         #endregion\r
329 \r
330         /// <summary>\r
331         /// Returns a code that throw the given expression\r
332         /// </summary>\r
333         /// <param name="throwExpression"></param>\r
334         /// <returns></returns>\r
335         public abstract string GetThrowStatement(string throwExpression);\r
336 \r
337         /// <summary>\r
338         /// Returns a declaration and assignement expression\r
339         /// </summary>\r
340         /// <param name="variableType"></param>\r
341         /// <param name="variableName"></param>\r
342         /// <param name="expression"></param>\r
343         /// <returns></returns>\r
344         public abstract string GetVariableDeclarationInitialization(string variableType, string variableName, string expression);\r
345 \r
346         /// <summary>\r
347         /// Writes the raw if.\r
348         /// </summary>\r
349         /// <param name="expression">The expression.</param>\r
350         public abstract void WriteRawIf(string expression);\r
351 \r
352         /// <summary>\r
353         /// Writes the raw else.\r
354         /// </summary>\r
355         public abstract void WriteRawElse();\r
356 \r
357         /// <summary>\r
358         /// Writes the raw endif.\r
359         /// </summary>\r
360         public abstract void WriteRawEndif();\r
361     }\r
362 }\r