#region MIT license // // MIT license // // Copyright (c) 2007-2008 Jiri Moudry, Pascal Craponne // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. // #endregion using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; using DbLinq.Util; using DbMetal.Generator; namespace DbMetal.Generator { /// /// Base class for writing code. /// Divided in 3 Parts: /// - Code line writing (with indentation) /// - Code formatting (returning a literal type) /// - Code writing (comment line, field, property, event...) /// public abstract class CodeWriter : TextWriter { // required by TextWriter public override Encoding Encoding { get { return TextWriter.Encoding; } } public string IndentationPattern { get; set; } private readonly StringBuilder buffer = new StringBuilder(10 << 10); private int currentindentation = 0; protected TextWriter TextWriter; protected CodeWriter(TextWriter textWriter) { IndentationPattern = "\t"; TextWriter = textWriter; } #region Writer protected bool IsFullLine() { int endIndex = buffer.Length - CoreNewLine.Length; if (endIndex < 0) return false; for (int i = 0; i < CoreNewLine.Length; i++) { if (buffer[endIndex + i] != CoreNewLine[i]) return false; } return true; } protected string GetLine() { string line = buffer.ToString(); buffer.Remove(0, buffer.Length); return line; } protected abstract bool MustIndent(string line); protected abstract bool MustUnindent(string line); /// /// In the end, all output comes to this /// /// public override void Write(char value) { buffer.Append(value); if (IsFullLine()) { string line = GetLine(); string rawLine = Trim(line); // unindent before... if (MustUnindent(rawLine)) currentindentation--; WriteLine(rawLine, currentindentation); // indent after if (MustIndent(rawLine)) currentindentation++; } } protected virtual string Trim(string line) { return line.Trim(); } protected virtual void WriteLine(string rawLine, int indentation) { if (!string.IsNullOrEmpty(rawLine)) { for (int indentationCount = 0; indentationCount < indentation; indentationCount++) { TextWriter.Write(IndentationPattern); } } TextWriter.WriteLine(rawLine); } public virtual string GetEnumType(string name) { return name; } public abstract IDisposable WriteEnum(SpecificationDefinition specificationDefinition, string name); public virtual void WriteEnum(SpecificationDefinition specificationDefinition, string name, IDictionary values) { using (WriteEnum(specificationDefinition, name)) { var orderedValues = from nv in values orderby nv.Value select nv; int currentValue = 1; foreach (var nameValue in orderedValues) { if (nameValue.Value == currentValue) WriteLine(string.Format("{0},", nameValue.Key)); else { currentValue = nameValue.Value; WriteLine(string.Format("{0} = {1},", nameValue.Key, nameValue.Value)); } currentValue++; } } } #endregion #region Code generation // A language sometimes generates complementary text, such as "{" and "}", or "#region"/"#endregion" protected class NestedInstruction : IDisposable { private readonly Action endAction; public NestedInstruction(Action end) { endAction = end; } public void Dispose() { endAction(); } } /// /// Registers an "end block" (written on Dispose() call) /// /// /// protected IDisposable EndAction(Action end) { return new NestedInstruction(end); } #endregion #region Code generation - Language write public abstract void WriteCommentLine(string line); public virtual void WriteCommentLines(string comments) { string[] commentLines = comments.Split('\n'); foreach (string commentLine in commentLines) { WriteCommentLine(commentLine.TrimEnd()); } } /// /// Registers namespace to be written /// /// public abstract void WriteUsingNamespace(string name); public abstract IDisposable WriteNamespace(string name); public abstract IDisposable WriteClass(SpecificationDefinition specificationDefinition, string name, string baseClass, params string[] interfaces); public abstract IDisposable WriteRegion(string name); public abstract IDisposable WriteAttribute(AttributeDefinition attributeDefinition); public abstract IDisposable WriteCtor(SpecificationDefinition specificationDefinition, string name, ParameterDefinition[] parameters, IList baseCallParameters); public abstract IDisposable WriteMethod(SpecificationDefinition specificationDefinition, string name, Type returnType, params ParameterDefinition[] parameters); public abstract IDisposable WriteProperty(SpecificationDefinition specificationDefinition, string name, string propertyType); public abstract void WriteAutomaticPropertyGetSet(); public abstract IDisposable WritePropertyGet(); public abstract IDisposable WritePropertySet(); public abstract void WritePropertyWithBackingField(SpecificationDefinition specificationDefinition, string name, string propertyType, bool privateSetter); public virtual void WritePropertyWithBackingField(SpecificationDefinition specificationDefinition, string name, string propertyType) { WritePropertyWithBackingField(specificationDefinition, name, propertyType, false); } public abstract void WriteField(SpecificationDefinition specificationDefinition, string name, string fieldType); public abstract void WriteEvent(SpecificationDefinition specificationDefinition, string name, string eventDelegate); public abstract IDisposable WriteIf(string expression); #endregion #region Code generation - Language construction public abstract string GetCastExpression(string value, string castType, bool hardCast); public virtual string GetLiteralValue(object value) { if (value == null) return GetNullExpression(); if (value is string) return string.Format("\"{0}\"", value); return value.ToString(); } public virtual string GetLiteralType(Type type) { return type.Name; } public virtual string GetLiteralFullType(Type type) { return type.FullName; } public virtual string GetMemberExpression(string obj, string member) { return string.Format("{0}.{1}", obj, member); } public virtual string GetReturnStatement(string expression) { if (expression == null) return GetStatement("return"); return GetStatement(string.Format("return {0}", expression)); } /// /// Returns the specified variable as a safe expression /// /// /// public abstract string GetVariableExpression(string name); public virtual string GetNewExpression(string ctor) { return string.Format("new {0}", ctor); } public virtual string GetThisExpression() { return "this"; } public virtual string GetDeclarationExpression(string variable, string type) { return string.Format("{0} {1}", type, variable); } public virtual string GetAssignmentExpression(string variable, string expression) { return string.Format("{0} = {1}", variable, expression); } public abstract string GetArray(string array, string literalIndex); public virtual string GetMethodCallExpression(string method, params string[] literalParameters) { return string.Format("{0}({1})", method, string.Join(", ", literalParameters)); } public virtual string GetStatement(string expression) { return expression; } public abstract string GetPropertySetValueExpression(); public abstract string GetNullExpression(); public abstract string GetGenericName(string baseName, string type); public abstract string GetDifferentExpression(string a, string b); public abstract string GetEqualExpression(string a, string b); public abstract string GetXOrExpression(string a, string b); public abstract string GetAndExpression(string a, string b); public abstract string GetTernaryExpression(string conditionExpression, string trueExpression, string falseExpression); public abstract string GetNullValueExpression(string literalType); #endregion /// /// Returns a code that throw the given expression /// /// /// public abstract string GetThrowStatement(string throwExpression); /// /// Returns a declaration and assignement expression /// /// /// /// /// public abstract string GetVariableDeclarationInitialization(string variableType, string variableName, string expression); /// /// Writes the raw if. /// /// The expression. public abstract void WriteRawIf(string expression); /// /// Writes the raw else. /// public abstract void WriteRawElse(); /// /// Writes the raw endif. /// public abstract void WriteRawEndif(); } }